SpringBoot自动配置的原理及实现/SpringBoot之@Import注解正确使用方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot自动配置的原理及实现/SpringBoot之@Import注解正确使用方式相关的知识,希望对你有一定的参考价值。

参考技术A https://www.jianshu.com/p/6b2f672e2446
了解SpringBoot之@Import注解正确使用方式

SpringBoot 的核心就是自动配置,自动配置又是基于条件判断来配置 Bean。关于自动配置的源码在 spring-boot -autoconfigure-2.0.3.RELEASE.jar

在通常需要我们在 property 中配置信息时,通常使用 @ConfigurationProperties(pefix=“前缀”) 注解的方式从配置文件中获取配置,如下:

application.yml 中配置信息

访问 url 获取配置信息返回的值
http://localhost:8080/msg

如果把 application.yml 中的配置信息注释掉则默认使用 default 值,否则使用配置信息中的值,以上便是普通配置方式

SpringBoot 运行原理
先看 @SpringBootApplication

主要关注的几个注解如下
@SpringBootConfiguration:标记当前类为配置类
@EnableAutoConfiguration:开启自动配置
@ComponentScan:扫描主类所在的同级包以及下级包里的 Bean
关键是 @EnableAutoConfiguration

最关键的要属 @Import(EnableAutoConfigurationImportSelector.class),借助** EnableAutoConfigurationImportSelector**,@EnableAutoConfiguration 可以帮助 SpringBoot 应用将所有符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建并使用的 IoC 容器: 通过 @Import(AutoConfigurationImportSelector.class) 导入的配置功能,
AutoConfigurationImportSelector 中的方法 getCandidateConfigurations,得到待配置的 class 的类名集合, 这个集合就是所有需要进行自动配置的类,而是是否配置的关键在于 META-INF/spring.factories 文件中是否存在该配置信息

打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔, 而 \ 表示忽略换行

整个流程如上图所示

以 SpringApplicationAdminJmxAutoConfiguration 类来看其主要构成部分

都能看到各种各样的条件判断注解,满足条件时就加载这个 Bean 并实例化
此类的条件注解是:@ConditionalOnProperty

@ConditionalOnBean:当容器里有指定 Bean 的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于 SpEL 表达式为 true 的时候作为判断条件才去实例化
@ConditionalOnJava:基于 JVM 版本作为判断条件
@ConditionalOnJndi:在 JNDI 存在的条件下查找指定的位置
@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
@ConditionalOnMissingClass:当容器里没有指定类的情况下
@ConditionalOnWebApplication:当前项目时 Web 项目的条件下
@ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnOnSingleCandidate:当指定 Bean 在容器中只有一个,或者有多个但是指定首选的 Bean
这些注解都组合了 @Conditional 注解,只是使用了不同的条件组合最后为 true 时才会去实例化需要实例化的类,否则忽略
这种 spring4.X 带来的动态组合很容易后期配置,从而避免了硬编码,使配置信息更加灵活多变,同时也避免了不必要的意外异常报错。使用的人只要知道配置的条件即可也不用去阅读源码,方便快捷,这也是 sprignboot 快捷方式带来的好处

参考 HttpEncodingAutoConfiguration 配置信息如下

案例扩展

项目

需要实例化的服务类

配置信息对应的属性映射类, 需要 pom 中加入 spring-boot-starter 依赖

自动配置文件

在创建如下路径文件 src/main/resources/META-INF/spring.factories

必须是自动配置类的全路径

mvn install 该项目

创建一个 springboot-mvc 项目 pom 依赖上面的 jar

http://localhost:8080 / 则返回当前服务的默认值

在 applicaton.yml 中加, 重启刷新则会更新为如下信息

SpringBoot 自动化配置关键组件关系图
mybatis-spring-boot-starter、spring-boot-starter-web 等组件的 META-INF 文件下均含有 spring.factories 文件,自动配置模块中,SpringFactoriesLoader 收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的 bean。

在 spring boot 中有时候需要控制配置类是否生效, 可以使用 @ConditionalOnProperty 注解来控制 @Configuration 是否生效.

SpringBoot自动配置的实现原理

一,配置属性类

其实就是值对象注入的方式去配置一些Spring常用的配置,我们编写一个最简单的配置对象。

@ConfigurationProperties(prefix = "hello")

//@Component //如果这里添加了注解那么在自动配置类的时候就不用添加@enableConfigurationProperties(HelloProperties.class)注解.

public class HelloProperties {

    private String msg="default";//现在我们在配置文件写hello.msg=world,因为简单就不再展示;如果那么默认为default.

    public String getMsg() {

        return msg;

    }

    public void setMsg(String msg) {

        this.msg = msg;

    }

}

这是一个简单的属性值对象,那么相当于写死的字段就是SpringBoot为我们自动配置的配置,那么我们很多时候可以自己在application.properties中修改某些配置就是这样的道理,我们不设置就是默认的,设置了就是我们设置的属性。

二,自动配置类

上面已经构建了我们简单的属性对象,那么现在我们要通过属性对象得到相应的属性值将其注入到我们的Bean中,这些Bean也就是一些SpringBoot启动后为我们自动配置生成的Bean,当然SpringBoot优先使用我们配置的Bean这个功能是如何实现的,我们往下看一下就明白了。

首先我们需要一个功能Bean,可以把这个Bean看做是SpringBoot框架启动后在容器里面生成的为我们服务的内置Bean,简单的写一个。

//@Component 这里很重要,如果我们添加了这个注解那么,按照我们下面的设置SpringBoot会优先使用我们配置的这个Bean,这是符合SpringBoot框架优先使用自定义Bean的原则的。

public class HelloService {

    private String msg = "service";//如果自动配置没有读入成功,那么为默认值

    public String say() {

        return "hello " + msg;

    }//为我们服务的方法

    public String getMsg() {

        return msg;

    }

    public void setMsg(String msg) {

        this.msg = msg;

    }

}

现在编写我们的自动配置类。

@Configuration //配置类

@EnableConfigurationProperties(HelloProperties.class)//这里就是前面说的,这个注解读入我们的配置对象类

@ConditionalOnClass(HelloService.class)//当类路径存在这个类时才会加载这个配置类,否则跳过,这个很有用比如不同jar包间类依赖,依赖的类不存在直接跳过,不会报错

public class HelloAutoConfiguration {

    @Autowired

    private HelloProperties helloProperties;

    @Bean

    @ConditionalOnMissingBean(HelloService.class)//这个配置就是SpringBoot可以优先使用自定义Bean的核心所在,如果没有我们的自定义Bean那么才会自动配置一个新的Bean

    public HelloService auto(){

        HelloService helloService =new HelloService();

        helloService.setMsg(helloProperties.getMsg());

        return helloService;

    }

}

好了现在自动配置的类也写好了,我们可以启动一下SpringBoot应用,测试一下。

三,测试自动配置

@SpringBootApplication

@RestController

public class MyRun {

    @Autowired

    private HelloService helloService;

    @RequestMapping("/auto/home")

    public String home(){

        return helloService.say();

    }

    public static void main(String[] args) {

        SpringApplication.run(MyRun.class,args);

    }

}

ok ,运行后访问你会看到:

hello world

代表我们的自动配置功能成功。

四,SpringBoot管理自动配置

其实在很多时候我们的配置是在很多jar包里的,那么我们新的应用该怎么读入这些jar包里的配置文件呢,SpringBoot是这样管理的。

最主要的注解就是@enableAutoConfiguration,而这个注解会导入一个EnableAutoConfigurationImportSelector的类,而这个类会去读取一个spring.factories下key为EnableAutoConfiguration全限定名对应值.

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

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

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

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

org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\

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

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

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

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

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\

org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\

org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\

org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\

org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\

org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\

org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\

org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\

org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\

org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\

org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\

org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\

org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\

org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\

org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\

org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\

org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\

org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\

org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\

org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\

org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\

org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\

org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\

org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\

org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\

org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\

org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\

org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\

org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\

org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

所以如果需要我们可以在我们的resources目录下创建spring.factories下添加类似的配置即可。

以上是关于SpringBoot自动配置的原理及实现/SpringBoot之@Import注解正确使用方式的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot自动配置原理及如何创建自己的Starter

Spring Boot核心原理实现及核心注解类

面试题: SpringBoot 的自动配置原理及定制starter

SpringBoot原理深入及源码剖析

Spring Boot 自动化配置原理带图全面讲解

springboot自动配置原理以及手动实现配置类