Springboot的自动装配 @SpringBootApplication 在启动类中有@SpringBootApplication注解,点开@SpringBootApplication的源码我们发现 它是由多个注解组合成的一个注解,其中@SpringBootConfiguration也是个组合注解,表示该类为配置类 而@EnableAutoConfiguratio才是自动配置的核心注解
1 2 3 4 5 6 7 8 9 10 11 12 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { }
@EnableAutoConfiguratio 点开@EnableAutoConfiguration可以发现一个@Import注解,也就是说这里可以导入一个或多个配置类 接着在查看AutoConfigurationImportSelector.class
1 2 3 4 5 6 7 8 9 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
AutoConfigurationImportSelector 可以发现他实现了一个DeferredImportSelector接口,而DeferredImportSelector接口继承了ImportSelector接口 这说明AutoConfigurationImportSelector是实现ImportSelector接口的类 也就是AutoConfigurationImportSelector可以通过selectImports方法返回多个配置类到@EnableAutoConfiguratio的@import注解中 在以下代码中可以看出返回值的数据源是通过getAutoConfigurationEntry方法获取的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class AutoConfigurationImportSelector implements DeferredImportSelector , BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
点开getAutoConfigurationEntry方法 getAutoConfigurationEntry是AutoConfigurationImportSelector中的方法 点开getCandidateConfigurations方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected AutoConfigurationEntry getAutoConfigurationEntry (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 = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry (configurations, exclusions); }
getCandidateConfigurations方法 getCandidateConfigurations是AutoConfigurationImportSelector中的方法 我们可以发现META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports的路径 也就是说selectImports方法返回值中的数据是来自AutoConfiguration.imports这个文件
1 2 3 4 5 6 7 8 9 protected List<String> getCandidateConfigurations (AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = new ArrayList <>( SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct." ); return configurations; }
AutoConfiguration.imports 在AutoConfiguration.imports有许多自动配置类的全类名 我们拿DispatcherServletAutoConfiguration举例 DispatcherServletAutoConfiguration中通过注解可以发现他是个配置类,其中有一个注解是@ConditionalOnClass(DispatcherServlet.Class)也就是在当前环境中有DispatcherServlet的类该配置类生效 DispatcherServletAutoConfiguration中有个DispatcherServletConfiguration配置类,且该配置类中有一个dispatcherServlet方法,返回了一个dispatcherServlet类,并且该方法添加了@Bean从而生成了DispatcherServlet做到了自动配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) public class DispatcherServletAutoConfiguration { @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties(WebMvcProperties.class) protected static class DispatcherServletConfiguration { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet (WebMvcProperties webMvcProperties) { DispatcherServlet dispatcherServlet = new DispatcherServlet (); dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents()); dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails()); return dispatcherServlet; } } }
总结
1.在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解 2.EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类 3.实现selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为Imports的文件,当然了,boot2.7以前的版本,读取的是spring.factories文件, 4.读取到全类名了之后,会解析注册条件,也就是@Conditional以及其衍生注解,把满足注册条件的Bean对象自动注入到Ioc容器中
自动装配的案例 准备一个jar包
准备一个带@Bean的配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Configuration public class MyConfig { @Bean @ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet") public Teacher getTeacher () { return new Teacher (); } @Bean @ConditionalOnMissingBean(Teacher.class) @ConfigurationProperties(prefix = "student") public Student getStudent () { return new Student (); } }
准备一个自动配置类 1 2 3 4 5 6 @AutoConfiguration @Import(MyConfig.class) public class MyAutoConfig { public MyAutoConfig () { } }
实体类 省略
将自动配置类的全类名添加到org.springframework.boot.autoconfigure.AutoConfiguration.imports中
打包成jar包 省略
将jar包保存到maven本地仓库 打开cmd输入 mvn install:install-file “-Dfile=C:\Users\23224\Desktop\demo16-0.0.1-SNAPSHOT.jar” “-DgroupId=demo16” “-DartifactId=reggie-demo16” “-Dversion=1.0” “-Dpackaging=jar”
导入依赖 1 2 3 4 5 <dependency > <groupId > demo16</groupId > <artifactId > reggie-demo16</artifactId > <version > 1.0</version > </dependency >
在启动类中测试 1 2 3 4 5 6 7 8 @SpringBootApplication public class Demo15Application { public static void main (String[] args) { ApplicationContext run = SpringApplication.run(Demo15Application.class, args); Teacher bean = run.getBean(Teacher.class); System.out.println(bean); } }