catalog
1,getAutoConfigurationMetadata
1) , get the exclude and excludeName property values of the EnableAutoConfiguration annotation
2) , get spring.factories Configuration value of EnableAutoConfiguration in
4) , get the classes that need to be excluded (not automatically assembled)
5) , checkExcludedClasses (check items to be excluded)
6) , send AutoConfigurationImportEvent event
7) , create AutoConfigurationEntry object return
Continue to the previous article, know the execution time and call order, continue to analyze the logic of the two methods, and how to realize automatic assembly. Take a look at its class structure (properties) autoconfigu before you start rationImportSelector.AutoConfigurationGroup
private static class AutoConfigurationGroup implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware { // Store annotation object relationships private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>(); // Store auto assembled data private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>(); private ClassLoader beanClassLoader; private BeanFactory beanFactory; private ResourceLoader resourceLoader; // Store automatically assembled, post processor, default order value and other information private AutoConfigurationMetadata autoConfigurationMetadata; }
1, process
@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { // Assertion judgment, definitely true Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, // Omit some codes); // Transition up, calling the method of the parent class AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); // Add to autoConfigurationEntries property this.autoConfigurationEntries.add(autoConfigurationEntry); // Add bean information to entries (map < string, annotationmetadata >) for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } }
Get the return result of AutoConfigurationEntry type, and assemble the data into autoConfigurationEntries and entries of AutoConfigurationGroup. The main method is in getAutoConfigurationMetadata, but autoConfigurationMetadata data is loaded before calling.
1,getAutoConfigurationMetadata
private AutoConfigurationMetadata getAutoConfigurationMetadata() { if (this.autoConfigurationMetadata == null) { this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); } return this.autoConfigurationMetadata; }
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) { // String PATH = "META-INF/spring-autoconfigure-metadata.properties"; return loadMetadata(classLoader, PATH); } static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) { try { Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path) : ClassLoader.getSystemResources(path); Properties properties = new Properties(); while (urls.hasMoreElements()) { properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement()))); } return loadMetadata(properties); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex); } }
The file path of the query is "meta-inf / spring autoconfigure"- metadata.Properties ", there are 488 key and value corresponding values in total. And load its value as property type data. Take a look at the general contents of the configuration file:
org...RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration org...CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate org...JerseyAutoConfiguration.AutoConfigureOrder=-2147483648
There are roughly three types (follow-up spring.factories Automatic assembly class in, condition judgment, filter and use):
1),... XXAutoConfiguration.AutoConfigureAfter Who's the type of auto assembled postprocessor
2),... XXAutoConfiguration.ConditionalOnClass Whose automatic assembly conditions
3),... XXAutoConfiguration.AutoConfigureorder Whose auto assemble sort field value
Continue to see the last added type (it's better to add the type of PropertiesAutoConfigurationMetadata, which is stored in the Properties type of Spring, which is a Hashtable):
static AutoConfigurationMetadata loadMetadata(Properties properties) { return new PropertiesAutoConfigurationMetadata(properties); }
2,getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
1) , get the exclude and excludeName property values of the EnableAutoConfiguration annotation
Only by default, @ EnableAutoConfiguration is directly used by @ SpringBootApplication, so the obtained property values are all default values (empty).
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { // org.springframework.boot.autoconfigure.EnableAutoConfiguration String name = getAnnotationClass().getName(); AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true)); Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?"); return attributes; }
2) , get spring.factories Configuration value of EnableAutoConfiguration in
You need to view the loaded type before calling:
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
When starting the Spring Boot project, meta-inf will be loaded after analysis/ spring.factories All configuration information in. In the case of correct process, it will be applied in spring
ation.run Method, when loading the SpringApplicationRunListener type, the information in the properties will be loaded. One of the items is roughly as follows:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ . . . . . .
3) , removedduplicates
protected final <T> List<T> removeDuplicates(List<T> list) { return new ArrayList<>(new LinkedHashSet<>(list)); }
Although it's relatively simple, it's a way we can learn from when we write a project.
4) , get the classes that need to be excluded (not automatically assembled)
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { Set<String> excluded = new LinkedHashSet<>(); excluded.addAll(asList(attributes, "exclude")); excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); excluded.addAll(getExcludeAutoConfigurationsProperty()); return excluded; }
Not only the configuration value on @ EnableConfiguration loaded by getAttributes, but also the value loaded in Environment in getExcludeAutoConfigurationsProperty. Of course, all values are empty by default.
5) , checkExcludedClasses (check items to be excluded)
Loop through the excluded items. If there is no item to be excluded in the auto assembly item, the assembly checks the exception IllegalStateException and throws it. So you can't just write exclusions.
6) . exclude
// Remove the exclusions according to the above exclusion set configurations.removeAll(exclusions); // According to the loaded spring autoconfigure- metadata.properties Conditions, excluding configurations = filter(configurations, autoConfigurationMetadata);
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; candidates[i] = null; skipped = true; } } } if (!skipped) { return configurations; } List<String> result = new ArrayList<>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList<>(result); }
1) , get first spring.factories AutoConfigurationImportFilter type in.
# Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition,\ org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
2) , traverse the above three types, and call back the three types of BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware and ResourceLoaderAware interfaces to assign values.
3) , combined with spring autoconfigure- metadata.properties The specific type loaded in is determined by calling the match method.
4) . the type of final automatic assembly after assembly and filtering. Return.
6) , send AutoConfigurationImportEvent event
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } } }
Get the event listening list, traverse the callback Aware interface, and send the AutoConfigurationImportEvent event event.
The monitor list is also automatically assembled spring.factories AutoConfigurationImportListener type in.
7) , create AutoConfigurationEntry object return
Create an AutoConfigurationEntry type object return based on the type list to be automatically assembled and the object list to be excluded to prepare for the subsequent selectImports callback.
2, selectImports
@Override public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream) .collect(Collectors.toSet()); Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); processedConfigurations.removeAll(allExclusions); return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); }
1) , get the HashSet to be excluded from list < autoconfigurationentry > autoconfigurationentries
2) , from List < autoconfigurationentry > autoconfigurationentries, get the auto assembled List and convert it to LinkedHashSet
3) . remove the items to be excluded from the automatic assembly list
4) Sort the auto assembly items and assemble them into de ferredImportSelector.Group.Entry Type, return.