首页 > 编程知识 正文

Spring Boot 自动配置Enable的秘密,spring自动配置

时间:2023-05-05 10:45:26 阅读:227094 作者:3222

在Spring Boot项目中,我们只需要引入spring-boot-start-web就能使用web开发相关的功能,而不需要添加任何配置。其实Spring Boot帮我们做好了很多的自动配置,在应用启动的时候依托于@EnableAutoConfiguration注解来激活自动配置的模块。本文中的@Enable和@Conditional我并没有细说,这两部分内容在我之前的文章中有详细的阐述。如果读者并不这两部分内容熟悉的话,请先读我的另外的两篇文章。之前的文章中探究了@Enable***用来激活指定的配置模块和使用@Conditional实现条件配置,在这个基础上再来看这个这个自动配置就非常简单了,我们一起去看一看。

演示环境 IntelliJ IDEA 2018.2.1 (Community Edition)Maven 3.5.4Spring Boot 2.1.1.RELEASE 走进源码

这里我们就以Web模块为例,来说明一下这个自动装配的怎么实现的。正常情况下我们的启动类上都会标注@SpringBootApplication,在这个@SpringBootApplication注解里面我们会发现@EnableAutoConfiguration用来激活我们的自动配置模块。

@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 {}

而这个@EnableAutoConfiguration注解里面使用了***ImportSelector,用来实现对自动配置类的筛选。

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}

而这个AutoConfigurationImportSelector这个类,又借助了工厂加载机制,根据@EnableAutoConfiguration注解的全类名去加载META-INF/spring.factories文件中配置好的自动配置的模块。

public class AutoConfigurationImportSelectorimplements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());} 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;}// 省略其它方法....... }

spring-boot-autoconfigure-2.1.1.RELEASE包下的META-INF/spring.factories文件:

# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,

上面的代码,一些不是我们叙述重点的都被我省略了。

然后去加载这个WebMvcAutoConfiguration的配置:

@Configuration@ConditionalOnWebApplication(type = Type.SERVLET)@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })public class WebMvcAutoConfiguration {}

首先这个WebMvcAutoConfiguration类是一个被@Configuration的配置类;然后它被标注了很多@ConditionalOn***的条件配置的条件,只有都满足条件了才会被容器装载;接着还定义了一些加载的顺序,以及在哪些配置的类之后加载。到这儿我们的web模块就被装载完成了。

实现自动配置

根据上面我们分析好的流程,我们可以自定义实现我们的自动配置。流程如下:

定义一个***AutoConfiguration的一个自动配置的类。使用@Enable***,用来激活我们自定义的某些配置模块。使用@ConditionalOn***,来根据自定义条件灵活的加载我们的 配置类。利用工厂加载机制,将我们的配置类配到META-INF/spring.factories文件中去。使用@EnableAutoConfiguration激活自动配置,验证我们的实现。 1、定义一个HelloAutoConfiguration

我们首先编写HelloAutoConfiguration的自动配置类:

/** * Hello模块自动装配 * * @author Jerome Zhu */@Configuration // 模式注解@EnableHello // Enable Hello模块装配 ↑@ConditionalOnSystemProperty(key = "user.name", value = "user") // 条件装配 ↑public class HelloAutoConfiguration { @Bean public String sayHello() { return "hello jerome, this is auto-configure."; }}

这里使用@Configuration表明这是一个配置类,使用我们@EnableHello用来激活我们自定义的Hello模块。使用@ConditionalOnSystemProperty用来判断系统参数是否满足我们制定的参数。

我的当前电脑的user.name的值为user。

2、使用@Enable***,激活模块配置

之前文章中编写好的@EnableHello注解:

/** * 激活Hello模块配置 * * @author Jerome Zhu */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(HelloConfiguration.class) // 模块装配:注解驱动实现public @interface EnableHello {}

以及HelloConfiguration配置类:

/** * Hello模块的配置 * * @author Jerome Zhu */@Configurationpublic class HelloConfiguration { @Bean public String hello() { // method key is bean key System.out.println("Bean : hello is loading."); return "hello word !"; }}

这里就激活了我们的自定义的Hello模块,会向容器中添加一个名为hello的javaBean。

3、使用@ConditionalOn***,判断自定义条件

之前文章中编写好的@ConditionalOnSystemProperty注解:

/** * 根据系统环境条件判断是否装配Bean * * @author Jerome Zhu */@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE, ElementType.METHOD })@Documented@Conditional(OnSystemPropertyCondition.class)public @interface ConditionalOnSystemProperty { /** * system property key */ String key(); /** * system property key */ String value();}

以及OnSystemPropertyCondition类:

/** * {@link Condition} 实现匹配系统配置的条件 * * @author Jerome Zhu */public class OnSystemPropertyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName()); String propertyKey = String.valueOf(attributes.get("key")); String propertyValue = String.valueOf(attributes.get("value")); // 获取系统变量 propertyKey 对应的值 String sysPropertyValue = System.getProperty(propertyKey); return propertyValue.equals(sysPropertyValue); }}

这里的条件配置就是判断当前系统变量中的属性,是否与我们限制的值相同,相同则向容器中注册。

4、添加自动配置类到META-INF/spring.factories文件中。

在我们的项目的resources文件夹下,新建META-INF文件夹,在该文件夹下新建spring.factories并添加一下配置:

# 添加自动装配org.springframework.boot.autoconfigure.EnableAutoConfiguration=xin.jerome.autoconfigure.configuration.HelloAutoConfiguration 5、验证自定义自动配置

我们编写一个启动类EnableHelloAutoConfigurationBootstrap来验证我们的配置是否生效。

/** * 使用spring boot 的自动装配 * {@link EnableAutoConfiguration} -> 丰富的蜜粉-INF/spring.factories 取到相应的配置 * * @author Jerome Zhu */@EnableAutoConfigurationpublic class EnableHelloAutoConfigurationBootstrap { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloAutoConfigurationBootstrap.class) .web(WebApplicationType.NONE) .run(args); String helloBean = context.getBean("hello", String.class); System.out.println("hello Bean: " + helloBean); String sayHelloBean = context.getBean("sayHello", String.class); System.out.println("sayHello Bean: " + sayHelloBean); context.close(); }}

首先使用@EnableAutoConfiguration激活自动配置模块,因为我们的@Enable ->HelloConfiguration注册了一个名为hello的javaBean,我们的HelloAutoConfiguration配置注册了一个名为sayHello的javaBean。我们根据上下文去获取我们的javaBean,并输出其内容。

当我们运行过后,控制台会有如下输出:

hello Bean: hello word !sayHello Bean: hello jerome, this is auto-configure.

说明我们的自定义自动装配模块成功了。

总结

其实自动装配模块的有这么几个要点,一是使用@Enable***模块用来激活我们的某一个功能模块;二是通过@Conditional***根据条件灵活的绝对是否要注册该组件,三是添加我们配置好的自动配置类到spring.factories文件中,让Spring Boot提供的自动配置模块去读取并加载它。

具体的代码可以参考GitHub:spring-boot-demo-autoconfigure小节。

原文地址:Spring Boot 自动配置@Enable的秘密

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。