ãŸããå°ãæŽå²ã æ°å¹ŽåããCUBAãã©ãããã©ãŒã ã§äŒæ¥ã¢ããªã±ãŒã·ã§ã³ãäœæããŠããŸãã ãããã¯ãµã€ãºãšæ©èœãéåžžã«ç°ãªããŸããã1ã€ã¯ãã¹ãŠäŒŒãŠããŸã-å€ãã®ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ããããŸãã
ããæç¹ã§ããµãŒããŒãåžžã«åèµ·åããŠãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ãéçºããã®ã¯éåžžã«é¢åã§ããããšãããããŸããã ãããã¹ã¯ããã®äœ¿çšã«ã¯å€§ããªå¶éããããŸãïŒãã£ãŒã«ããã¯ã©ã¹ã¡ãœãããè¿œå ããã³ååå€æŽããããšã¯ã§ããŸããïŒã åãµãŒããŒã®åèµ·åã«ã¯å°ãªããšã10ç§ããããããã«åãã°ã€ã³ããŠéçºäžã®ç»é¢ã«ç§»åããå¿ èŠããããŸããã
å®å šãªããããããã€ã«ã€ããŠèããå¿ èŠããããŸããã ã¢ã³ããŒã«ãã-ã³ãŒããšãã¢ã¢ããªã±ãŒã·ã§ã³ã®åé¡ã«å¯Ÿããåœç€Ÿã®ãœãªã¥ãŒã·ã§ã³ã
èæ¯
CUBAãã©ãããã©ãŒã ã§ã®ç»é¢ã®éçºã«ã¯ãç»é¢ã®å®£èšåXMLèšè¿°åã®äœæãå«ãŸããŸããããã¯ãã³ã³ãããŒã©ãŒã¯ã©ã¹ã®ååã瀺ããŸãã ãããã£ãŠãã¹ã¯ãªãŒã³ã³ã³ãããŒã©ãŒã¯ã©ã¹ã¯åžžã«ãã«ããŒã ã§ååŸãããŸãã
ãŸããã»ãšãã©ã®å Žåãã¹ã¯ãªãŒã³ã³ã³ãããŒã©ãŒã¯ããèªäœã®ãã®ã§ããããšã«æ³šæããå¿ èŠããããŸããã€ãŸããä»ã®ã³ã³ãããŒã©ãŒãã¯ã©ã¹ã ãã§ã¯äœ¿çšãããŸããïŒããã¯èµ·ãããŸãããé »ç¹ã§ã¯ãããŸããïŒã
æåã«ãGroovyã䜿çšããŠããããããã€ã®åé¡ã解決ããããšããŸããã ãœãŒã¹Groovyã³ãŒãã®ãµãŒããŒãžã®ããŠã³ããŒããéå§ããGroovyClassLoaderãä»ããŠã¹ã¯ãªãŒã³ã³ã³ãããŒã©ãŒã®ã¯ã©ã¹ãååŸããŸããã ããã«ããããµãŒããŒãžã®å€æŽã®é ä¿¡é床ã§åé¡ã解決ããŸããããå€ãã®æ°ããåé¡ãçºçããŸããïŒåœæã®Groovyã¯IDEã®ãµããŒããæ¯èŒç貧匱ã§ãåçãªåä»ãã«ãããçµéšã®æµ ãéçºè ã«æ°ä»ãããã«ã³ã³ãã€ã«ãããŠããªãã³ãŒããæžãããšãã§ããŸãããããããããšãã§ããŸãã
ãããžã§ã¯ãã«ã¯äœçŸãã®ç»é¢ããããããããããã€ã§ãå£ããå¯èœæ§ããããããç»é¢ã³ã³ãããŒã©ãŒã§ã®Groovyã®äœ¿çšãæŸæ£ããå¿ èŠããããŸããã
ããããç§ãã¡ã¯äžçæžåœã«èããŸããã ãµãŒããŒãžã®ã³ãŒãã®å³æé ä¿¡ïŒåèµ·åãªãïŒã®å©ç¹ãåŸããšåæã«ãã³ãŒãã®å質ãããŸãå±éºã«ããããªãããã«ãããã£ãã®ã§ãã Java 1.6ã«ç»å Žããæ©èœ-ToolProvider.getSystemJavaCompilerïŒïŒïŒIBM.comã®èª¬æ ïŒ ãå©ãã«ãªããŸãã ã ãã®ãªããžã§ã¯ãã䜿çšãããšããœãŒã¹ã³ãŒãããjava.lang.Classåã®ãªããžã§ã¯ããååŸã§ããŸãã è©ŠããŠã¿ãããšã«ããŸããã
å®è£
ã¯ã©ã¹ããŒããŒãGroovyClassLoaderã«äŒŒããã®ã«ããããšã«ããŸããã ã³ã³ãã€ã«ãããã¯ã©ã¹ããã£ãã·ã¥ããã¯ã©ã¹ã«ã¢ã¯ã»ã¹ãããã³ã«ãã¯ã©ã¹ã®ãœãŒã¹ã³ãŒãããã¡ã€ã«ã·ã¹ãã äžã§æŽæ°ããããã©ããã確èªããŸãã æŽæ°ããããšãã³ã³ãã€ã«ãéå§ãããçµæããã£ãã·ã¥ã«ä¿åãããŸãã
ãªã³ã¯ãã¯ãªãã¯ãããšãã¯ã©ã¹ããŒããŒã®è©³çŽ°ãªå®è£ ã確èªã§ããŸãã
ãã®èšäºã§ã¯ãå®è£ ã®éèŠãªãã€ã³ãã«çŠç¹ãåœãŠãŸãã
ã¡ã€ã³ã¯ã©ã¹ã§ããJavaClassLoaderããå§ããŸãããã
ççž®JavaClassLoaderã³ãŒã
public class JavaClassLoader extends URLClassLoader implements ApplicationContextAware { ..... protected final Map<String, TimestampClass> compiled = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Lock> locks = new ConcurrentHashMap<>(); protected final ProxyClassLoader proxyClassLoader; protected final SourceProvider sourceProvider; protected XmlWebApplicationContext applicationContext; private static volatile boolean refreshing = false; ..... @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = (XmlWebApplicationContext) applicationContext; this.applicationContext.setClassLoader(this); } public Class loadClass(final String fullClassName, boolean resolve) throws ClassNotFoundException { String containerClassName = StringUtils.substringBefore(fullClassName, "$"); try { lock(containerClassName); Class clazz; if (!sourceProvider.getSourceFile(containerClassName).exists()) { clazz = super.loadClass(fullClassName, resolve); return clazz; } CompilationScope compilationScope = new CompilationScope(this, containerClassName); if (!compilationScope.compilationNeeded()) { return getTimestampClass(fullClassName).clazz; } String src; try { src = sourceProvider.getSourceString(containerClassName); } catch (IOException e) { throw new ClassNotFoundException("Could not load java sources for class " + containerClassName); } try { log.debug("Compiling " + containerClassName); final DiagnosticCollector<JavaFileObject> errs = new DiagnosticCollector<>(); SourcesAndDependencies sourcesAndDependencies = new SourcesAndDependencies(rootDir, this); sourcesAndDependencies.putSource(containerClassName, src); sourcesAndDependencies.collectDependencies(containerClassName); Map<String, CharSequence> sourcesForCompilation = sourcesAndDependencies.collectSourcesForCompilation(containerClassName); @SuppressWarnings("unchecked") Map<String, Class> compiledClasses = createCompiler().compile(sourcesForCompilation, errs); Map<String, TimestampClass> compiledTimestampClasses = wrapCompiledClasses(compiledClasses); compiled.putAll(compiledTimestampClasses); linkDependencies(compiledTimestampClasses, sourcesAndDependencies.dependencies); clazz = compiledClasses.get(fullClassName); updateSpringContext(); return clazz; } catch (Exception e) { proxyClassLoader.restoreRemoved(); throw new RuntimeException(e); } finally { proxyClassLoader.cleanupRemoved(); } } finally { unlock(containerClassName); } } private void updateSpringContext() { if (!refreshing) { refreshing = true; applicationContext.refresh(); refreshing = false; } } ..... /** * Add dependencies for each class and ALSO add each class to dependent for each dependency */ private void linkDependencies(Map<String, TimestampClass> compiledTimestampClasses, Multimap<String, String> dependecies) { for (Map.Entry<String, TimestampClass> entry : compiledTimestampClasses.entrySet()) { String className = entry.getKey(); TimestampClass timestampClass = entry.getValue(); Collection<String> dependencyClasses = dependecies.get(className); timestampClass.dependencies.addAll(dependencyClasses); for (String dependencyClassName : timestampClass.dependencies) { TimestampClass dependencyClass = compiled.get(dependencyClassName); if (dependencyClass != null) { dependencyClass.dependent.add(className); } } } } ..... }
loadClassãåŒã³åºããšãã次ã®ã¢ã¯ã·ã§ã³ãå®è¡ããŸãã
- ãã®ã¯ã©ã¹ã®ãœãŒã¹ã³ãŒãããã¡ã€ã«ã·ã¹ãã ã«ãããã©ããã確èªãããªãå Žåã¯ãç¶æ¿ãããloadClassãåŒã³åºããŸã
- ã³ã³ãã€ã«ãå¿ èŠãã©ããã確èªããŸããããšãã°ãã¯ã©ã¹ã®ãœãŒã¹ã³ãŒããå«ããã¡ã€ã«ãå€æŽãããŠããŸãã ããã§ã¯ãã¯ã©ã¹ã§ã®1ãã¡ã€ã«ã®å€æŽã ãã§ãªãããã¹ãŠã®äŸåé¢ä¿ã远跡ããŠããããšãèŠããŠããå¿ èŠããããŸã
- äŸåé¢ä¿ãåéããŸã-ã³ã³ãã€ã«ããã¯ã©ã¹ã«äŸåãããã¹ãŠã®ãã®ãšãäŸåãããã¹ãŠã®ãã®
- ã³ã³ãã€ã«ã®ããã«åäŸåé¢ä¿ããã§ãã¯ããã³ã³ãã€ã«ããå¿ èŠããªããã®ãæšãŠãŸã
- ãœãŒã¹ã³ãŒããã³ã³ãã€ã«ããŸã
- çµæããã£ãã·ã¥ã«å ¥ãã
- å¿ èŠã«å¿ããŠãSpringã³ã³ããã¹ããæŽæ°ãã
- èŠæ±ãããã¯ã©ã¹ãè¿ããŸã
updateSpringContextïŒïŒã¡ãœããã«æ³šæãæããšãã¯ã©ã¹ãããŒãããããã³ã«Springã³ã³ããã¹ããæŽæ°ãããŸãã ããã¯ãã¢ã¢ããªã±ãŒã·ã§ã³ã§è¡ãããŸããããå®éã®ãããžã§ã¯ãã§ã¯ããã®ãããªé »ç¹ãªã³ã³ããã¹ãã®æŽæ°ã¯éåžžå¿ èŠãããŸããã
誰ããçåã«æããããããŸãã-ã¯ã©ã¹ãäŸåãããã®ãã©ã®ããã«æ±ºå®ããã®ã§ããïŒ çãã¯ç°¡åã§ã-ã€ã³ããŒãã»ã¯ã·ã§ã³ã解æããŸãã 以äžã¯ãããè¡ãã³ãŒãã§ãã
äŸåé¢ä¿ã³ã¬ã¯ã·ã§ã³ã³ãŒãã
class SourcesAndDependencies { private static final String IMPORT_PATTERN = "import (.+?);"; private static final String IMPORT_STATIC_PATTERN = "import static (.+)\\..+?;"; public static final String WHOLE_PACKAGE_PLACEHOLDER = ".*"; final Map<String, CharSequence> sources = new HashMap<>(); final Multimap<String, String> dependencies = HashMultimap.create(); private final SourceProvider sourceProvider; private final JavaClassLoader javaClassLoader; SourcesAndDependencies(String rootDir, JavaClassLoader javaClassLoader) { this.sourceProvider = new SourceProvider(rootDir); this.javaClassLoader = javaClassLoader; } public void putSource(String name, CharSequence sourceCode) { sources.put(name, sourceCode); } /** * Recursively collects all dependencies for class using imports * * @throws java.io.IOException */ public void collectDependencies(String className) throws IOException { CharSequence src = sources.get(className); List<String> importedClassesNames = getDynamicallyLoadedImports(src); String currentPackageName = className.substring(0, className.lastIndexOf('.')); importedClassesNames.addAll(sourceProvider.getAllClassesFromPackage(currentPackageName));//all src from current package for (String importedClassName : importedClassesNames) { if (!sources.containsKey(importedClassName)) { addSource(importedClassName); addDependency(className, importedClassName); collectDependencies(importedClassName); } else { addDependency(className, importedClassName); } } } /** * Decides what to compile using CompilationScope (hierarchical search) * Find all classes dependent from those we are going to compile and add them to compilation as well */ public Map<String, CharSequence> collectSourcesForCompilation(String rootClassName) throws ClassNotFoundException, IOException { Map<String, CharSequence> dependentSources = new HashMap<>(); collectDependent(rootClassName, dependentSources); for (String dependencyClassName : sources.keySet()) { CompilationScope dependencyCompilationScope = new CompilationScope(javaClassLoader, dependencyClassName); if (dependencyCompilationScope.compilationNeeded()) { collectDependent(dependencyClassName, dependentSources); } } sources.putAll(dependentSources); return sources; } /** * Find all dependent classes (hierarchical search) */ private void collectDependent(String dependencyClassName, Map<String, CharSequence> dependentSources) throws IOException { TimestampClass removedClass = javaClassLoader.proxyClassLoader.removeFromCache(dependencyClassName); if (removedClass != null) { for (String dependentName : removedClass.dependent) { dependentSources.put(dependentName, sourceProvider.getSourceString(dependentName)); addDependency(dependentName, dependencyClassName); collectDependent(dependentName, dependentSources); } } } private void addDependency(String dependent, String dependency) { if (!dependent.equals(dependency)) { dependencies.put(dependent, dependency); } } private void addSource(String importedClassName) throws IOException { sources.put(importedClassName, sourceProvider.getSourceString(importedClassName)); } private List<String> unwrapImportValue(String importValue) { if (importValue.endsWith(WHOLE_PACKAGE_PLACEHOLDER)) { String packageName = importValue.replace(WHOLE_PACKAGE_PLACEHOLDER, ""); if (sourceProvider.directoryExistsInFileSystem(packageName)) { return sourceProvider.getAllClassesFromPackage(packageName); } } else if (sourceProvider.sourceExistsInFileSystem(importValue)) { return Collections.singletonList(importValue); } return Collections.emptyList(); } private List<String> getDynamicallyLoadedImports(CharSequence src) { List<String> importedClassNames = new ArrayList<>(); List<String> importValues = getMatchedStrings(src, IMPORT_PATTERN, 1); for (String importValue : importValues) { importedClassNames.addAll(unwrapImportValue(importValue)); } importValues = getMatchedStrings(src, IMPORT_STATIC_PATTERN, 1); for (String importValue : importValues) { importedClassNames.addAll(unwrapImportValue(importValue)); } return importedClassNames; } private List<String> getMatchedStrings(CharSequence source, String pattern, int groupNumber) { ArrayList<String> result = new ArrayList<>(); Pattern importPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); Matcher matcher = importPattern.matcher(source); while (matcher.find()) { result.add(matcher.group(groupNumber)); } return result; } }
æ°é ãã®ããèªè ã¯å°ããŸã-ã³ã³ãã€ã«èªäœã¯ã©ãã§ããïŒ ä»¥äžã¯åœŒå¥³ã®ã³ãŒãã§ãã
CharSequenceCompilerã·ã§ãŒãã³ãŒã
public class CharSequenceCompiler<T> { ..... // The compiler instance that this facade uses. private final JavaCompiler compiler; public CharSequenceCompiler(ProxyClassLoader loader, Iterable<String> options) { compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { throw new IllegalStateException("Cannot find the system Java compiler. " + "Check that your class path includes tools.jar"); } ..... } ..... public synchronized Map<String, Class<T>> compile( final Map<String, CharSequence> classes, final DiagnosticCollector<JavaFileObject> diagnosticsList) throws CharSequenceCompilerException { List<JavaFileObject> sources = new ArrayList<JavaFileObject>(); for (Map.Entry<String, CharSequence> entry : classes.entrySet()) { String qualifiedClassName = entry.getKey(); CharSequence javaSource = entry.getValue(); if (javaSource != null) { final int dotPos = qualifiedClassName.lastIndexOf('.'); final String className = dotPos == -1 ? qualifiedClassName : qualifiedClassName.substring(dotPos + 1); final String packageName = dotPos == -1 ? "" : qualifiedClassName .substring(0, dotPos); final JavaFileObjectImpl source = new JavaFileObjectImpl(className, javaSource); sources.add(source); // Store the source file in the FileManager via package/class // name. // For source files, we add a .java extension javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName, className + JAVA_EXTENSION, source); } } // Get a CompliationTask from the compiler and compile the sources final JavaCompiler.CompilationTask task = compiler.getTask(null, javaFileManager, diagnostics, options, null, sources); final Boolean result = task.call(); if (result == null || !result) { StringBuilder cause = new StringBuilder("\n"); for (Diagnostic d : diagnostics.getDiagnostics()) { cause.append(d).append(" "); } throw new CharSequenceCompilerException("Compilation failed. Causes: " + cause, classes .keySet(), diagnostics); } try { // For each class name in the input map, get its compiled // class and put it in the output map Map<String, Class<T>> compiled = new HashMap<String, Class<T>>(); for (String qualifiedClassName : classLoader.classNames()) { final Class<T> newClass = loadClass(qualifiedClassName); compiled.put(qualifiedClassName, newClass); } return compiled; } catch (ClassNotFoundException e) { throw new CharSequenceCompilerException(classes.keySet(), e, diagnostics); } catch (IllegalArgumentException e) { throw new CharSequenceCompilerException(classes.keySet(), e, diagnostics); } catch (SecurityException e) { throw new CharSequenceCompilerException(classes.keySet(), e, diagnostics); } } ...... }
ããã¯ã©ã®ããã«åœ¹ç«ã¡ãŸããïŒ
ãã®èšäºã§ã¯ã Spring MVCã§å°ããªã¢ããªã±ãŒã·ã§ã³ãäœæã ãããã§ã¯ã©ã¹ããŒããŒã䜿çšããŸããã
ãã®ã¢ããªã¯ãåçã³ã³ãã€ã«ã®ã¡ãªãããå®æŒããŸãã
WelcomeControllerãšSpring-bean SomeBeanã¯ãã¢ããªã±ãŒã·ã§ã³ã§å®£èšãããŠããŸãã ã³ã³ãããŒã©ãŒã¯SomeBean.getïŒïŒã¡ãœããã䜿çšããçµæã衚瀺ã¬ãã«ã«æ»ããŸãã
次ã«ãã¯ã©ã¹ããŒããŒã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ãåæ¢ããã«SomeBeanImplãšWelcomeControllerã®å®è£ ãå€æŽããæ¹æ³ã瀺ããŸãã ãŸããã¢ããªã±ãŒã·ã§ã³ããããã€ãïŒãã«ãããã«ã¯gradleãå¿ èŠã§ãïŒã localhostã«åãæ¿ããŸãïŒ8080 / mvcclassloader / helloã
çãã¯ãWelcomeControllerããããã«ã¡ã¯ã ããŒãžã§ã³ïŒãªããŒããããŠããŸããã
次ã«ãSomeBeanImplã®å®è£ ãå°ãå€æŽããŸãããã
@Component("someBean") public class SomeBeanImpl implements SomeBean { @Override public String get() { return "reloaded";// not reloaded } }
ãã¡ã€ã«ããµãŒããŒäžã®ãã©ã«ããŒtomcat / conf / com / haulmont / mvcclassloaderã«é 眮ããŸãïŒã¯ã©ã¹ããŒããŒããœãŒã¹ã³ãŒããæ€çŽ¢ãããã©ã«ããŒã¯ãmvc-dispatcher-servlet.xmlãã¡ã€ã«ã§æ§æãããŸãïŒã 次ã«ãã¯ã©ã¹ã®ããŒããåŒã³åºãå¿ èŠããããŸãã ãããè¡ãããã«ãå¥ã®ã³ã³ãããŒã©ãŒ-ReloadControllerãäœæããŸããã å®éã«ã¯ãå€åã¯ããŸããŸãªæ¹æ³ã§æ€åºã§ããŸãããããã¯ãã¢ã³ã¹ãã¬ãŒã·ã§ã³ã«é©ããŠããŸãã ReloadControllerã¯ãã¢ããªã±ãŒã·ã§ã³ã®2ã€ã®ã¯ã©ã¹ããªããŒãããŸãã ãªã³ã¯localhost ïŒ8080 / mvcclassloader / reloadãã¯ãªãã¯ããŠãã³ã³ãããŒã©ãŒãåŒã³åºãããšãã§ããŸãã
ãã®åŸãå床localhostã«åãæ¿ããŸãïŒ8080 / mvcclassloader / helloïŒ
WelcomeControllerããããã«ã¡ã¯ã ããŒãžã§ã³ïŒåèªã¿èŸŒã¿ã
ããããããã ãã§ã¯ãããŸããã WebControllerã®ã³ãŒããå€æŽããããšãã§ããŸãã ãã£ãŠã¿ãŸãããã
@Controller("welcomeController") public class WelcomeController { @Autowired protected SomeBean someBean; @RequestMapping(value = "/hello", method = RequestMethod.GET) public ModelAndView welcome() { ModelAndView model = new ModelAndView(); model.setViewName("index"); model.addObject("version", someBean.get() + " a bit more");// a bit more return model; } }
ã¯ã©ã¹ã®ãªããŒããåŒã³åºããŠã¡ã€ã³ã³ã³ãããŒã©ãŒã«ã¢ã¯ã»ã¹ãããšã次ã®ããã«è¡šç€ºãããŸãã
WelcomeControllerããããã«ã¡ã¯ã ããŒãžã§ã³ïŒããå°ããªããŒãããŸããã
ãã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¯ã©ã¹ããŒããŒã¯ã¯ã©ã¹ãã³ã³ãã€ã«ãããã³ã«ã³ã³ããã¹ããå®å šã«ãªããŒãããŸãã 倧èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ã®å Žåãããã«ã¯ããªãã®æéããããå¯èœæ§ããããããå¥ã®æ¹æ³ããããŸã-ã³ã³ãã€ã«ãããã³ã³ããã¹ãå ã®ã¯ã©ã¹ã®ã¿ãå€æŽã§ããŸãã ãã®æ©äŒã¯DefaultListableBeanFactoryã«ãã£ãŠæäŸãããŸãã ããšãã°ãCUBAãã©ãããã©ãŒã ã§ã¯ãSpringã³ã³ããã¹ãã®ã¯ã©ã¹çœ®æã¯æ¬¡ã®ããã«å®è£ ãããŸãã
private void updateSpringContext(Collection<Class> classes) { if (beanFactory != null) { for (Class clazz : classes) { Service serviceAnnotation = (Service) clazz.getAnnotation(Service.class); ManagedBean managedBeanAnnotation = (ManagedBean) clazz.getAnnotation(ManagedBean.class); Component componentAnnotation = (Component) clazz.getAnnotation(Component.class); Controller controllerAnnotation = (Controller) clazz.getAnnotation(Controller.class); String beanName = null; if (serviceAnnotation != null) { beanName = serviceAnnotation.value(); } else if (managedBeanAnnotation != null) { beanName = managedBeanAnnotation.value(); } else if (componentAnnotation != null) { beanName = componentAnnotation.value(); } else if (controllerAnnotation != null) { beanName = controllerAnnotation.value(); } if (StringUtils.isNotBlank(beanName)) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(clazz); beanFactory.registerBeanDefinition(beanName, beanDefinition); } } } }
ããã§ã®ããŒã¯ãæååbeanFactory.registerBeanDefinitionïŒbeanNameãbeanDefinitionïŒã§ãã
ããã«ã¯åŸ®åŠãªç¹ã1ã€ãããŸã-DefaultListableBeanFactoryã¯ããã©ã«ãã§äŸåBeanããªãŒããŒããŒãããªããããå°ã調æŽããå¿ èŠããããŸããã
public class CubaDefaultListableBeanFactory extends DefaultListableBeanFactory { ..... /** * Reset all bean definition caches for the given bean, * including the caches of beans that depends on it. * * @param beanName the name of the bean to reset */ protected void resetBeanDefinition(String beanName) { String[] dependentBeans = getDependentBeans(beanName); super.resetBeanDefinition(beanName); if (dependentBeans != null) { for (String dependentBean : dependentBeans) { resetBeanDefinition(dependentBean); registerDependentBean(beanName, dependentBean); } } } }
ãµãŒããŒã«å€æŽãè¿ éã«é ä¿¡ããæ¹æ³
ãµãŒããŒãåèµ·åããã«ãµãŒããŒåŽã®Javaã¢ããªã±ãŒã·ã§ã³ã«å€æŽãé ä¿¡ããã«ã¯ãããã€ãã®æ¹æ³ããããŸãã
æåã®æ¹æ³ã¯ããã¡ããæšæºã®Javaãããã¬ãŒã«ãã£ãŠæäŸããããããã¹ã¯ããã§ãã ããã«ã¯æãããªæ¬ ç¹ããããŸã-ã¯ã©ã¹ã®æ§é ãå€æŽïŒã¡ãœããããã£ãŒã«ãã®è¿œå ãå€æŽïŒããããšã¯ã§ããŸããããããã«ããµãŒããŒã§äœ¿çšããããšã¯éåžžã«åé¡ã§ãã
2çªç®ã®æ¹æ³ã¯ããµãŒãã¬ããã³ã³ããã«ãã£ãŠæäŸãããããããããã€ã§ãã åã«warãã¡ã€ã«ããµãŒããŒã«ã¢ããããŒããããšãã¢ããªã±ãŒã·ã§ã³ãåã³èµ·åããŸãã ãã®æ¹æ³ã«ã¯æ¬ ç¹ããããŸãã ãŸããã¢ããªã±ãŒã·ã§ã³å šäœãåæ¢ããŸããã€ãŸãããã°ããå©çšã§ããªãããšãæå³ããŸãïŒã¢ããªã±ãŒã·ã§ã³ã®å±éæéã¯ã³ã³ãã³ãã«ãã£ãŠç°ãªããããªãã®æéããããå ŽåããããŸãïŒã 第äºã«ããããžã§ã¯ãå šäœã®çµã¿ç«ãŠã«ã¯ããèªäœããªãã®æéãããããŸãã 第äžã«ãå€æŽãæ£ç¢ºã«å¶åŸ¡ããèœåããªããããã©ããã§ãã¹ãããå Žåãã¢ããªã±ãŒã·ã§ã³ãå床ãããã€ããå¿ èŠããããŸãã
3çªç®ã®æ¹æ³ã¯ã2çªç®ã®æ¹æ³ã®ããªãšãŒã·ã§ã³ãšèããããšãã§ããŸãã ã¯ã©ã¹ãã¡ã€ã«ãweb-inf / classesãã©ã«ããŒïŒWebã¢ããªã±ãŒã·ã§ã³çšïŒã«é 眮ãããšããµãŒããŒã§äœ¿çšå¯èœãªã¯ã©ã¹ããªãŒããŒã©ã€ããããŸãã ãã®ã¢ãããŒãã«ã¯ãæ¢åã®ã¯ã©ã¹ãšã®ãã€ããªéäºææ§ãäœæããå¯èœæ§ããããã¢ããªã±ãŒã·ã§ã³ã®äžéšãåäœããªããªãå¯èœæ§ããããŸãã
4çªç®ã®æ¹æ³ã¯JRebelã§ãã 顧客ã®ãµãŒããŒã§ã䜿çšããŠãã人ããããšèããŸããããèªåã§ã¯ããŸããã åæã«ãéçºã«ãæé©ã§ãã 圌ã«ã¯1ã€ã®æ¬ ç¹ããããŸã-ããã«ã¯ããªãã®ãéãããããŸãã
5çªç®ã®æ¹æ³ã¯ãSpring Loadedã§ãã javaagentãä»ããŠæ©èœããŸãã ç¡æã§ãã ãã ããSpringã§ã®ã¿æ©èœããã¯ã©ã¹éå±€ãã³ã³ã¹ãã©ã¯ã¿ãªã©ãå€æŽããããšãã§ããŸããã
ãããŠãã¡ãããåçã«ã³ã³ãã€ã«ãããèšèªïŒGroovyãªã©ïŒããããŸãã æåã«ãããã«ã€ããŠæžããã
ç§ãã¡ã®ã¢ãããŒãã®åŒ·ã¿ã¯äœã§ãã
- å€æŽã®é ä¿¡ã¯éåžžã«é«éã§ãåèµ·åãã¢ããªã±ãŒã·ã§ã³ãå©çšã§ããŸãã
- åçã«ã³ã³ãã€ã«ãããã¯ã©ã¹ã®æ§é ãä»»æã«å€æŽã§ããŸãïŒã¯ã©ã¹éå±€ãã€ã³ã¿ãŒãã§ãŒã¹ãªã©ãå€æŽããŸãïŒã
- ãœãŒã¹ã³ãŒãã¯ã¯ãªã¢ããã¹ãã§ãµãŒããŒäžã«ãããããïŒããšãã°diffã䜿çšããŠïŒæ£ç¢ºã«å€æŽãããå 容ããã€ã§ã確èªã§ããŸãã
- ã¯ã©ã¹ã眮ãæããããã»ã¹ãå®å šã«å¶åŸ¡ããŸããããšãã°ãæ°ãããœãŒã¹ã³ãŒããã³ã³ãã€ã«ãããªãå Žåã¯ãã¯ã©ã¹ã®å€ãããŒãžã§ã³ãè¿ãããšãã§ããŸãã
- ãµãŒããŒäžã§ãã°ãçŽæ¥ç°¡åã«ä¿®æ£ã§ããŸãïŒãã®ãããªå ŽåããããŸãïŒ
- éçºè ã®ãµãŒããŒã«å€æŽãé ä¿¡ããæ©èœãIDEã«å®è£ ããã®ã¯éåžžã«ç°¡åã§ãïŒãœãŒã¹ã³ãŒããã³ããŒããã ãã§ïŒ
- ããªãã¯äžéã䜿ããŸãã
ãã¡ãããæ¬ ç¹ããããŸãã èšå®å€æŽã®ã¡ã«ããºã ã¯ããè€éã«ãªã£ãŠããŸãã äžè¬çãªã±ãŒã¹ã§ã¯ãå®è£ ããã®å Žã§å€æŽã§ããããã«ã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ãæ§ç¯ããå¿ èŠããããŸãïŒããšãã°ãã³ã³ã¹ãã©ã¯ã¿ãŒã䜿çšãããååã§ã¯ã©ã¹ãååŸãããªãã¬ã¯ã·ã§ã³ã䜿çšããŠãªããžã§ã¯ããäœæããŸãïŒã ã¯ã©ã¹ããŒãããã¯ã©ã¹ãååŸããã®ã«ãããæéã¯ãããã«å¢å ããŸãïŒãã¡ã€ã«ã·ã¹ãã ã®ãã§ãã¯ã®ããïŒã
ãã ããé©åãªã¢ãããŒãã§ã¯ãå©ç¹ã¯æ¬ ç¹ãã«ããŒãã以äžã®ãã®ã§ãã
çµè«ãšããŠãç§ãã¡ã¯ã¢ããªã±ãŒã·ã§ã³ã§ãã®ã¢ãããŒããçŽ5幎é䜿çšããŠãããšèšããããšæããŸãã 圌ã¯éçºäžã®æéãå€§å¹ ã«ç¯çŽããããã«ãµãŒããŒã®ãšã©ãŒãä¿®æ£ããã®ã«å€ãã®ç¥çµã䜿ããŸããã