Spring Boot自动配置原理、实战

Stella981
• 阅读 654

Spring Boot自动配置原理

Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射。

  1. org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)

  2. public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {

  3. String factoryClassName = factoryClass.getName();

  4. try {

  5. Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :

  6. lassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

  7. List<String> result = new ArrayList<String>();

  8. while (urls.hasMoreElements()) {

  9. URL url = urls.nextElement();

  10. Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));

  11. String factoryClassNames = properties.getProperty(factoryClassName);

  12. result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));

  13. }

  14. return result;

  15. }

  16. catch (IOException ex) {

  17. throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +

  18. "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);

  19. }

  20. }

这个方法会加载类路径及所有jar包下META-INF/spring.factories配置中映射的自动配置的类。

  1. /**

  2. * The location to look for factories.

  3. * <p>Can be present in multiple JAR files.

  4. */

  5. public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

查看Spring Boot自带的自动配置的包: spring-boot-autoconfigure-1.5.6.RELEASE.jar,打开其中的META-INF/spring.factories文件会找到自动配置的映射。

  1. # Auto Configure

  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

  3. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

  4. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

  5. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

  6. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

  7. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

  8. org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

  9. org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

  10. ...

再来看看数据源自动配置的实现注解

  1. @Configuration

  2. @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })

  3. @EnableConfigurationProperties(DataSourceProperties.class)

  4. @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })

  5. public class DataSourceAutoConfiguration {

  6. ...

@Configuration,@ConditionalOnClass就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

自动配置实战

所以,了解了自动配置的原理,来自己实现一个自动配置的玩意其实很简单。

添加配置类:

  1. import org.slf4j.Logger;

  2. import org.springframework.context.EnvironmentAware;

  3. import org.springframework.core.env.Environment;

  4. import com.oceanpayment.common.utils.logger.LoggerUtils;

  5. public class EnvConfig implements EnvironmentAware {

  6. private final Logger logger = LoggerUtils.getLogger(this);

  7. private Environment env;

  8. public String getStringValue(String key) {

  9. return env.getProperty(key);

  10. }

  11. public Long getLongValue(String key) {

  12. String value = getStringValue(key);

  13. try {

  14. return Long.parseLong(value);

  15. } catch (Exception e) {

  16. logger.error("字符串转换Long失败:{} = {}", key, value);

  17. }

  18. return 0L;

  19. }

  20. public int getIntValue(String key) {

  21. return getLongValue(key).intValue();

  22. }

  23. @Override

  24. public void setEnvironment(Environment environment) {

  25. this.env = environment;

  26. }

  27. }

添加自动配置类:

  1. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

  2. import org.springframework.context.annotation.Bean;

  3. import org.springframework.context.annotation.Configuration;

  4. import org.springframework.core.env.PropertyResolver;

  5. @Configuration

  6. @ConditionalOnClass(PropertyResolver.class)

  7. public class EnvAutoConfig {

  8. @Bean

  9. public EnvConfig envConfig() {

  10. return new EnvConfig();

  11. }

  12. }

创建META-INF/spring.factories文件,添加自动配置映射:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\

  2. com.oceanpayment.common.config.env.EnvAutoConfig

这样就搞定了。

查看自动配置报告

怎么查看自己加的自动配置类有没有被加载,或者查看所有自动配置激活的和未激活的可以通过以下几种试查看。

  1. spring-boot:run运行的在对话框Enviroment中加入debug=true变量 

  2. java -jar xx.jar --debug

  3. main方法运行,在VM Argumanets加入-Ddebug

  4. 直接在application文件中加入debug=true

  5. 如果集成了spring-boot-starter-actuator监控,通过autoconfig端点也可以查看。

启动后会在控制台看到以下自动配置报告信息:

  1. =========================

  2. AUTO-CONFIGURATION REPORT

  3. =========================

  4. Positive matches:

  5. -----------------

  6. AopAutoConfiguration matched:

  7. - @ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

  8. - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

  9. ...

  10. EnvAutoConfig matched:

  11. - @ConditionalOnClass found required class 'org.springframework.core.env.PropertyResolver'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

  12. ErrorMvcAutoConfiguration matched:

  13. - @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

  14. - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)

  15. ErrorMvcAutoConfiguration#basicErrorController matched:

  16. - @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.ErrorController; SearchStrategy: current) did not find any beans (OnBeanCondition)

  17. ...

  18. Negative matches:

  19. -----------------

  20. ActiveMQAutoConfiguration:

  21. Did not match:

  22. - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)

  23. AopAutoConfiguration.JdkDynamicAutoProxyConfiguration:

  24. Did not match:

  25. - @ConditionalOnProperty (spring.aop.proxy-target-class=false) found different value in property 'proxy-target-class' (OnPropertyCondition)

  26. ArtemisAutoConfiguration:

  27. Did not match:

  28. - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory' (OnClassCondition)

  29. BatchAutoConfiguration:

  30. Did not match:

  31. - @ConditionalOnClass did not find required class 'org.springframework.batch.core.launch.JobLauncher' (OnClassCondition)

  32. ...

Positive matches:已经启用的自动配置

Negative matches:未启用的自动配置

从报告中看到自己添加的EnvAutoConfig已经自动配置了。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
springboot的起步依赖
!(https://oscimg.oschina.net/oscnet/f3acbe4cf3b00c68207e091c172d6b45a27.png)加载自动配置的方式2:!(https://oscimg.oschina.net/oscnet/40341228c10f7a56d82323a1d622521d92d.png) spring
Easter79 Easter79
3年前
SpringBoot自定义序列化的使用方式
场景及需求:项目接入了SpringBoot开发,现在需求是服务端接口返回的字段如果为空,那么自动转为空字符串。例如:\    {        "id":1,        "name":null    },    {        "id":2,        "name":"x
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
Unity横屏
Android下发现Unity里面的Player设置,并不能完全有效,比如打开了自动旋转,启动的时候还是会横屏,修改XML添加以下代码<applicationandroid:icon"@drawable/ic\_launcher"                    android:label"@string/app\_name"
Stella981 Stella981
3年前
SpringBoot自定义序列化的使用方式
场景及需求:项目接入了SpringBoot开发,现在需求是服务端接口返回的字段如果为空,那么自动转为空字符串。例如:\    {        "id":1,        "name":null    },    {        "id":2,        "name":"x
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这