本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等
我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序:
public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } |
和我们之前使用普通Spring时繁琐的配置相比简直不要太方便,那么你知道SpringBoot实现这些的原理么
首先我们看到类上方包含了一个@SpringBootApplication
注解
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { @AliasFor( annotation = EnableAutoConfiguration.class ) Class<?>[] exclude() default {}; @AliasFor( annotation = EnableAutoConfiguration.class ) String[] excludeName() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackages" ) String[] scanBasePackages() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackageClasses" ) Class<?>[] scanBasePackageClasses() default {}; } |
这个注解上边包含的东西还是比较多的,咱们先看一下两个简单的热热身
@ComponentScan
注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) |
这个注解咱们都是比较熟悉的,无非就是自动扫描并加载符合条件的Bean到容器中,这个注解会默认扫描声明类所在的包开始扫描,例如:
类cn.shiyujun.Demo
类上标注了@ComponentScan
注解,则cn.shiyujun.controller
、cn.shiyujun.service
等等包下的类都可以被扫描到
这个注解一共包含以下几个属性:
basePackages:指定多个包名进行扫描 basePackageClasses:对指定的类和接口所属的包进行扫 excludeFilters:指定不扫描的过滤器 includeFilters:指定扫描的过滤器 lazyInit:是否对注册扫描的bean设置为懒加载 nameGenerator:为扫描到的bean自动命名 resourcePattern:控制可用于扫描的类文件 scopedProxy:指定代理是否应该被扫描 scopeResolver:指定扫描bean的范围 useDefaultFilters:是否开启对@Component,@Repository,@Service,@Controller的类进行检测 |
@SpringBootConfiguration
注解
这个注解更简单了,它只是对Configuration
注解的一个封装而已
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { } |
EnableAutoConfiguration
注解
这个注解可是重头戏了,SpringBoot号称的约定大于配置,也就是本文的重点自动装配的原理就在这里了
@Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; } |
简单概括一下,这个注解存在的意义就是:利用@Import
注解,将所有符合自动装配条件的bean注入到IOC容器中,关于@Import
注解原理这里就不再阐述,感兴趣的同学可以参考此篇文章:Spring @Import注解源码解析
进入类AutoConfigurationImportSelector
,观察其selectImports
方法,这个方法执行完毕后,Spring会把这个方法返回的类的全限定名数组里的所有的类都注入到IOC容器中
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); } } |
观察上方代码:
- 第一行if时会首先判断当前系统是否禁用了自动装配的功能,判断的代码如下:
protected boolean isEnabled(AnnotationMetadata metadata) { return this.getClass() == AutoConfigurationImportSelector.class ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true; } |
- 如果当前系统禁用了自动装配的功能则会返回如下这个空的数组,后续也就无法注入bean了
private static final String[] NO_IMPORTS = new String[0];
|
-
此时如果没有禁用自动装配则进入else分枝,第一步操作首先会去加载所有Spring预先定义的配置条件信息,这些配置信息在
org.springframework.boot.autoconfigure
包下的META-INF/spring-autoconfigure-metadata.properties
文件中 -
这些配置条件主要含义大致是这样的:如果你要自动装配某个类的话,你觉得先存在哪些类或者哪些配置文件等等条件,这些条件的判断主要是利用了
@ConditionalXXX
注解,关于@ConditionalXXX
系列注解可以参考这篇文章:SpringBoot条件注解@Conditional -
这个文件里的内容格式是这样的:
org.springframework.boot.actuate.autoconfigure.web.servlet.WebMvcEndpointChildContextConfiguration.ConditionalOnClass=org.springframework.web.servlet.DispatcherServlet org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,io.micrometer.core.instrument.MeterRegistry org.springframework.boot.actuate.autoconfigure.flyway.FlywayEndpointAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration |
- 具体的加载代码就不列出了,无法就是个读取配置文件
- 这里放个加载之后的结果图:
- 获取
@EnableAutoConfiguration
注解上的exclude、excludeName属性,这两个属性的作用都是排除一些类的 - 这里又是关键的一步,可以看到刚才图片中spring-autoconfigure-metadata.properties文件的上方存在一个文件spring.factories,这个文件可就不止存在于
org.springframework.boot.autoconfigure
包里了,所有的包里都有可能存在这个文件,所以这一步是加载整个项目所有的spring.factories文件。这个文件的格式是这样的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoConfiguration,\org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration
|
- 这里存在一个知识点,SpringBoot中的star就是依靠这个文件完成的,假如我们需要自定义一个SpringBoot的Star,就可以在我们的项目的META-INF文件夹下新建一个spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.shiyujun.TestAutoConfiguration
|
这样当别的项目依赖我们的项目时就会自动把我们的TestAutoConfiguration
类注入到Spring容器中
- 删除重复的自动配置类
- 下面三行就是去除我们指定排除的配置类
- 接着这一行的逻辑稍微复杂一些,主要就是根据加载的配置条件信息来判断各个配置类上的
@ConditionalXXX
系列注解是否满足需求 - 最后就是发布自动装配完成事件,然后返回所有能够自动装配的类的全限定名
到了这里我们已经把SpringBoot自动装配的原理搞清楚了,但是总感觉差点什么,那我们从这些自动装配的类里面挑一个我们比较熟悉的关于Servlet的类来看看咋回事吧:
public class ServletEndpointManagementContextConfiguration { public ServletEndpointManagementContextConfiguration() { } public ExposeExcludePropertyEndpointFilter<ExposableServletEndpoint> servletExposeExcludePropertyEndpointFilter(WebEndpointProperties properties) { Exposure exposure = properties.getExposure(); return new ExposeExcludePropertyEndpointFilter(ExposableServletEndpoint.class, exposure.getInclude(), exposure.getExclude(), new String[0]); } public class JerseyServletEndpointManagementContextConfiguration { public JerseyServletEndpointManagementContextConfiguration() { } public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties, ServletEndpointsSupplier servletEndpointsSupplier) { return new ServletEndpointRegistrar(properties.getBasePath(), servletEndpointsSupplier.getEndpoints()); } } public class WebMvcServletEndpointManagementContextConfiguration { private final ApplicationContext context; public WebMvcServletEndpointManagementContextConfiguration(ApplicationContext context) { this.context = context; } public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties, ServletEndpointsSupplier servletEndpointsSupplier) { DispatcherServletPathProvider servletPathProvider = (DispatcherServletPathProvider)this.context.getBean(DispatcherServletPathProvider.class); String servletPath = servletPathProvider.getServletPath(); if (servletPath.equals("/")) { servletPath = ""; } return new ServletEndpointRegistrar(servletPath + properties.getBasePath(), servletEndpointsSupplier.getEndpoints()); } } } |
自上而下观察整个类的代码,你会发现这些自动装配的套路都是一样的
- 如果当前是Servlet环境则装配这个bean
- 当存在类
ResourceConfig
以及不存在类DispatcherServlet
时装配JerseyServletEndpointManagementContextConfiguration
- 当存在
DispatcherServlet
类时装配WebMvcServletEndpointManagementContextConfiguration
- 接下来如果还有面试官问你,你会了么?
相关推荐
Springboot 自动装配原理图文,里面描述了整个Springboot的装配流程和所有相关的组件。
深入源码底层分析springBoot自动装配原理并结合案例进行实战。
SpringBoot自动装配原理学习
SpringBoot自动装配原理
springboot自动装配的过程解析...
SpringBoot自动装配原理(简单易懂)
SpringBoot自动装配原理分析(初探)思维导图
1.基于SpringBoot自动装配,引用jar包即可,坐标如下: <groupId>com.glzt</groupId> <artifactId>feignextend <version>1.0.0-SNAPSHOT 2.基于logback、log4j的MDC机制 3.日志配置中添加traceId引用,如下: ...
pringboot自动装配原理(Av75233634,P6)
使用mindmaster打开
SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提。我们在熟练使用springboot的时候,能否也能熟悉它完整的自动装配的过程?该资源包含了:springboot自动装配主要节点流程图、springboot自动装配完整流程...
手动实现SpringBoot自动装配类 ,清测可用,代码详见com.auto包
#学习springboot自动装配 ##一,手动装配 ### 1,模式注解装配 @Component注解,或者@Component注解的扩展,@ Controller,@ Service,存储库,@ Configruation等, ### 2. @ Configuration启动容器+ @ Bean注册...
swagger-spring-boot-starter 是一款建立在swagger基础之上的工具包,利用SpringBoot自动装配的特性,简化了传统swagger的繁琐配置
主要介绍了Springboot自动装配实现过程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了SpringBoot启动及自动装配原理过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
,spring注解 热身,springboot 自动装配原理
springboot的自定义自动默认配置(如果你不配置属性,就按照默认的来,如果配置了就按照你的来)
使用mindmaster打开