Just do the back-end development, when the first contact is the basis of the spring, to quote a two-way package provides bean, also we need to increase the corresponding packet in the xml <context:component-scan base-package="xxx" />
or add notes @ComponentScan({ "xxx"})
. I felt very urgly, but did not go to study there a better way.
After the contact until the Spring Boot, bean found to be automatically incorporated second party package. But I did not see the realization of this principle. Until recently, when asked about the interview. So I looked under implementation logic.
Use gestures
Under the first principle speaks before use posture.
Bean defined in a project A in.
package com.wangzhi; import org.springframework.stereotype.Service; @Service public class Dog { }
And the project is resources/META-INF/
to create a named under the spring.factories
document, the document reads as follows
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wangzhi.Dog
Then reference project A jar package in the project B.
projectA code is as follows:
package com.wangzhi.springbootdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; @EnableAutoConfiguration public class SpringBootDemoApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoApplication.class, args); System.out.println(context.getBean(com.wangzhi.Dog.class)); } }
Print Results:
com.wangzhi.Dog@3148f668
Analytical principle
Overall is divided into two parts: First, collect all spring.factories
of the EnableAutoConfiguration
relevant class of the bean, the second is to get the class registration to spring container.
Class collection bean definition
In the spring when the container starts, it will call toAutoConfigurationImportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // EnableAutoConfiguration注解的属性:exclude,excludeName等 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 得到所有的Configurations List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去重 configurations = removeDuplicates(configurations); // 删除掉exclude中指定的类 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } getCandidateConfigurations会调用到方法loadFactoryNames: public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { // factoryClassName为org.springframework.boot.autoconfigure.EnableAutoConfiguration String factoryClassName = factoryClass.getName(); // 该方法返回的是所有spring.factories文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类路径 return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { // 找到所有的"META-INF/spring.factories" Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Resource a UrlResource = new new a UrlResource (url); // read the file contents, properties similar to HashMap, including key attributes and value the Properties the Properties = PropertiesLoaderUtils.loadProperties (Resource); for (Map.Entry <? ?,> entry: properties.entrySet ()) { String factoryClassName = . ((String) entry.getKey ()) TRIM (); // the attribute file can be used ',' a plurality of divided value for (String factoryName: StringUtils.commaDelimitedListToStringArray ((String ) entry.getValue ())) { result.add (factoryClassName, factoryName.trim ()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
Sign up to container
All obtained in the above process in spring.factories
the class specified in the path of the bean, the processGroupImports
process will be processed @import logic which annotations introduced into the same vessel.
public void processGroupImports () { for (DeferredImportSelectorGrouping GROUPING: the this .groupings.values ()) { // getImports i.e. class that encapsulates all the paths obtained above grouping.getImports () forEach (entry ->. { ConfigurationClass configurationClass = the this .configurationClasses .get ( entry.getMetadata ()); the try { // and process annotations as @Import processImports (configurationClass, asSourceClass (configurationClass), asSourceClasses (entry.getImportClassName ()), to false ); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Boolean processConfigurationClass (candidate.asConfigClass (the configClass));checkForCircularImports) { ... // traverse collected classpath for (SourceClass candidate: importCandidates) { ... // If the candidate is ImportSelector ImportBeanDefinitionRegistrar or the type of processing logic will be different, here not concerned // Candidate class Not AN or ImportBeanDefinitionRegistrar ImportSelector -> // process class IT AS AN @Configuration the this .importStack.registerImport ( . currentSourceClass.getMetadata (), candidate.getMetadata () the getClassName ()); // as @Configuration processing ... } .. . }
It can be seen in the bean class definition first step collected will eventually be to Configuration
the same treatment registered to the vessel.
End
@EnableAutoConfiguration
Annotations second party introduced simplified bean package cost. A second party contracted to provide other applications, only the second party bag exposed to the external bean definitions in spring.factories
just fine. For unwanted bean, consumers can use @EnableAutoConfiguration
the exclude
exclusion properties.
I compiled a free Java Advanced information, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo distributed high concurrency and other tutorials, a total of 30G, needs its own collection.
Portal: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q