一、springboot 自动配置原理
先说说我们自己的应用程序中Bean加入容器的办法:
package com.ynunicom.dc.dingdingcontractapp; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author jinye.Bai */ @SpringBootApplication( scanBasePackages ={"com.ynunicom.dc.dingdingcontractapp"} ) public class DingdingContractAppApplication { public static void main(String[] args) { SpringApplication.run(DingdingContractAppApplication.class, args); } }
我们在应用程序的入口设置了 @SpringBootApplication标签,默认情况下他会扫描所有次级目录。
如果增加了 scanBasePackages属性,就会扫描所有被指定的路径及其次级目录。
那么它在扫描的是什么东西呢?
是这个:@Component
所有被扫描到的 @Component,都会成为一个默认的singleton(单例,即一个容器里只有一个对象实体)加入到容器中。
认识到以上这点,便于我们理解springboot自动配置的机制。
接下来让我们看看在自己的应用程序中实现配置的方法。
如图:
package com.ynunicom.dc.dingdingcontractapp.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author: jinye.Bai * @date: 2020/5/22 15:51 */ @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
这里我们设置了一个配置,往容器中加入了一个RestTemplate。
首先说 @Configuration,这个标签继承了 @Component标签,我们可以在标签内容看到:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.context.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Component; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor( annotation = Component.class ) String value() default ""; }
可以看到其中是有 @Component标签的,所以,@Configuration会被 @SpringBootApplication扫描到,进而把它和它下面的 @Bean加入容器,于是我们 RestTemplate的内容就配置完成了,在后续的使用中,我们就可以直接从容器中拿出RestTemplate使用它。
对于在maven中引用的其他外部包加入容器的过程,需要用到spring.factories。
二、spring.factories文件的作用
在springboot运行时,SpringFactoriesLoader 类会去寻找
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
我们以mybatis-plus为例。
首先我们引入:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.2</version> </dependency>
然后去maven的依赖里看它的自动配置类MybatisPlusAutoConfiguration
@Configuration @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) @ConditionalOnSingleCandidate(DataSource.class) @EnableConfigurationProperties({MybatisPlusProperties.class}) @AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class}) public class MybatisPlusAutoConfiguration implements InitializingBean {