关于SpringBoot AutoConfiguration
(1)如何导入的自动配置类
首先我们得从@SpringBootApplication注解入手。
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
@SpringBootApplication = @EnableAutoConfiguration + @ComponentScan + @SpringBootConfiguration
@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 {
@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 {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
其中@EnableAutoConfiguration注解是一个组合注解,@AutoConfigurationPackage 表示自动配置包与@Import({AutoConfigurationImportSelector.class})
1、@AutoConfigurationPackage
作用:给Spring容器中导入一个Registrar注册组件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
@AutoConfigurationPackage和@ComponentScan一样,也是将主配置类所在的包以及子包里面的组件扫描到IOC容器中,但是区别是 @AutoConfigurationPackage扫描@Enitity、@MapperScan等第三方依赖的注解。 @ComponentScan只扫描@Controller、@Service、@Component、@Repository这些常见注解。所以说这俩注解的对象是不一样的。
2、@Import({AutoConfigurationImportSelector.class})
而@Import({AutoConfigurationImportSelector.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
在AutoConfigurationImportSelector下可以看到 getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
通过SpringFactoriesLoader.loadFactoryNames()

将spring-boot-autoconfigure-2.3.12.RELEASE.jar/META-INF/spring.factories 下配置导入configurations并返回。
总结自动装配的过程
1、通过各种注解的方式实现类与类之间的依赖关系,容器在启动的时候SpringApplication.run(),调用了EnableAutoConfigurationImportSelector.class的selectImports方法。
2、selectImporys方法调用了SpringFactoriesLoader.loadFactoryNames方法扫描jar包类路径下的META-INF/spring.factories文件下获取BEANConfiguration列表。
3、loadFactoryNames方法会读取spring.factoris文件中EnableAutoConfiguration.class类对应的值。
4、根据类上的注解判断,若符合条件则改配置类生效,将配置文件中的属性值配置到对应的配置类中,最后注入到IOC容器中实现自动配置。
(2)@Conditional 的魔力
为了让有条件性注册 Spring bean 变得更加灵活,Spring 4 引入了 @Conditional 概念。通过使用 @Conditional 方式,你可以根据任意条件注册一个 bean。
例如,你可能想在如下情况注册一个 bean:
- classpath 中某个类
- 某种类型的 Spring bean,尚未在 ApplicationContext 中注册
- 存放在某个位置的某个文件
- 一个存在于配置文件中的某个属性值
- 一个存在/不存在的某个系统属性
这里只是列举了几个例子,你可以根据自己的需要定义任何条件。
让我们来看看 Spring 的 @Conditional 是如何工作的。
假设我们有一个 UserDAO 接口,其包含从数据存储中获取数据的方法。我们有两个 UserDAO 接口的实现,即 JdbcUserDAO(与 MySQL 数据库通信)和 MongoUserDAO(与 MongoDB 通信)。
我们可能想通过基于系统属性 dbType 来只启用 JdbcUserDAO 或 MongoUserDAO 其中一个。
如果应用程序使用了 java -jar myapp.jar -DdbType = MySQL 启动,则启用 JdbcUserDAO,如果启动时使用了 java -jar myapp.jar -DdbType = MONGO,则启用 MongoUserDAO。
假设我们有 UserDAO 接口,以下是 JdbcUserDAO 和 MongoUserDAO 实现类:
public interface UserDAO
{
List<String> getAllUserNames();
}
public class JdbcUserDAO implements UserDAO
{
@Override
public List<String> getAllUserNames()
{
System.out.println("**** Getting usernames from RDBMS *****");
return Arrays.asList("Siva","Prasad","Reddy");
}
}
public class MongoUserDAO implements UserDAO
{
@Override
public List<String> getAllUserNames()
{
System.out.println("**** Getting usernames from MongoDB *****");
return Arrays.asList("Bond","James","Bond");
}
}
我们可以实现一个 MySQLDatabaseTypeCondition Condition 来检查系统属性是否是 MYSQL:
public class MySQLDatabaseTypeCondition implements Condition
{
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata)
{
String enabledDBType = System.getProperty("dbType");
return (enabledDBType != null && enabledDBType.equalsIgnoreCase("MYSQL"));
}
}
现在我们可以使用 @Conditional 条件性地配置 JdbcUserDAO 和 MongoUserDAO bean,如下所示:
@Configuration
public class AppConfig
{
@Bean
@Conditional(MySQLDatabaseTypeCondition.class)
public UserDAO jdbcUserDAO(){
return new JdbcUserDAO();
}
@Bean
@Conditional(MongoDBDatabaseTypeCondition.class)
public UserDAO mongoUserDAO(){
return new MongoUserDAO();
}
}
如果我们使用 java -jar myapp.jar -DdbType = MYSQL 来运行应用程序,则只有 JdbcUserDAO bean 被注册。
但如果将系统属性设置为 -DdbType = MONGODB,则只会注册 MongoUserDAO bean。
使用注解实现 Condition 的方式更为优雅,我们可以创建一个 DatabaseType 注解,如下所示:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(DatabaseTypeCondition.class)
public @interface DatabaseType
{
String value();
}
然后可以通过编写 DatabaseTypeCondition 使用 DatabaseType 的值来确定是否启用或禁用 bean 注册,如下所示:
public class DatabaseTypeCondition implements Condition
{
@Override
public boolean matches(ConditionContext conditionContext,
AnnotatedTypeMetadata metadata)
{
Map<String, Object> attributes = metadata.getAnnotationAttributes(DatabaseType.class.getName());
String type = (String) attributes.get("value");
String enabledDBType = System.getProperty("dbType","MYSQL");
return (enabledDBType != null && type != null && enabledDBType.equalsIgnoreCase(type));
}
}
现在我们可以将 @DatabaseType 注解放置在 bean 定义上:
@Configuration
@ComponentScan
public class AppConfig
{
@DatabaseType("MYSQL")
public UserDAO jdbcUserDAO(){
return new JdbcUserDAO();
}
@Bean
@DatabaseType("MONGO")
public UserDAO mongoUserDAO(){
return new MongoUserDAO();
}
}
此处,我们从 DatabaseType 注解获取元数据,并检查系统属性 dbType 的值以确定是否启用或禁用 bean 注册。
我们已经看了许多示例,了解了如何使用 @Conditional 注解条件性地注册 bean。
SpringBoot 大量地使用了 @Conditional 特性,根据各种标准条件性地注册 bean。
你可以在 Spring-boot-autoconfigure- {version} .jar 的 org.springframework.boot.autoconfigure 包中找到 SpringBoot 使用的各种 Condition 实现。
(3)如何关闭自动配置
全体无效化
a)使用@Configuration @ComponentScan 代替 @SpringBootApplication。
b)参数设置
src/main/resources/application.properties
设置spring.boot.enableautoconfiguration=false
部分无效化
@SpringBootApplication(exclude=HibernateJpaAutoConfiguration.class)
或
src/main/resources/application.properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
@SpringBootApplication(exclude={DataSourceAutoConfiguration.**class**, DataSourceTransactionManagerAutoConfiguration.**class**, HibernateJpaAutoConfiguration.**class**})
或
src/main/resources/application.properties
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
spring.autoconfigure.exclude[3]=org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
以上内容均来自下面三篇文章,本人只是自己做了个总结,方便以后学习,如有侵权,请告知我,马上删除!
引用:
SpringBoot自动装配以及原理 - Be_Your_Sun - 博客园 (cnblogs.com)
Spring Boot 入门 - 进阶篇(7)- 自动配置(AutoConfigure) - Fish Where The Fish Are - ITeye博客
了解 Spring Boot AutoConfiguration - oopsguy - 博客园 (cnblogs.com)
了解 Spring Boot AutoConfiguration - oopsguy - 博客园 (cnblogs.com)
关于SpringBoot AutoConfiguration的更多相关文章
- spring-boot autoConfiguration
一, 第一个待注入类 public class CacheService { } public class LoggerService { } 方法一, 实现接口ImportSelectort pub ...
- 了解 Spring Boot AutoConfiguration
原文:http://sivalabs.in/2016/03/how-springboot-autoconfiguration-magic/ 作者:Siva 译者:http://oopsguy.com ...
- spring boot 四大组件之Auto Configuration
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- springboot 自定义starter之AutoConfiguration【原】
八.自定义starter AutoConfiguration: 1.这个场景需要使用到的依赖是什么? 没有特别依赖的配置 2.如何编写自动配置 @Configuration //指定这个类是一个配置类 ...
- SpringBoot四大神器之auto-configuration
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- SpringBoot使用AutoConfiguration自定义Starter
https://segmentfault.com/a/1190000011433487
- Debug - SpringBoot - Error starting ApplicationContext. To display the auto-configuration report re-runyour application
Error log 2019-12-07 22:33:03.959 ERROR 3760 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : ** ...
- Springboot搭建web项目
最近因为项目需要接触了springboot,然后被其快速零配置的特点惊呆了.关于springboot相关的介绍我就不赘述了,大家自行百度google. 一.pom配置 首先,建立一个maven项目,修 ...
- SpringBoot前世今生
序 本文主要讲述spring boot的由来,即其它诞生的背景,初衷,现状,及对未来的展望. 背景 在很早的年代,J2EE还是java企业级应用的王者规范,EJB风行其道.后来有一个叫Rod John ...
- SpringBoot常用配置简介
SpringBoot常用配置简介 1. SpringBoot中几个常用的配置的简单介绍 一个简单的Spring.factories # Bootstrap components org.springf ...
随机推荐
- 自己动手从零写桌面操作系统GrapeOS系列教程——13.向MBR中写入程序
学习操作系统原理最好的方法是自己写一个简单的操作系统. 前面铺垫了这么久,今天终于开始写程序了.本讲将介绍3个逐步深入但非常简单的程序,一方面是让大家熟悉开发流程,另一方面是顺便解决前面遇到的CPU占 ...
- 组合计数中的q-模拟 q analog
拒绝更新,深度和广度上建议看这个pdf URL里面用到的一些query-string过期了,,, 论文题目是 THE q-SERIES IN COMBINATORICS; PERMUTATION ST ...
- CSAPP-Shell Lab
提供的工具: parseline:获取参数列表char **argv,返回是否为后台运行命令(true). clearjob:清除job结构. initjobs:初始化jobs链表. maxjid:返 ...
- Rancher 系列文章-K3s Traefik MiddleWare 报错-Failed to create middleware keys
概述 书接上回:<Rancher 系列文章-K3S 集群升级>, 我们提到:通过一键脚本升级 K3S 集群有报错. 接下来开始进行 Traefik 报错的分析和修复, 问题是: 所有 Tr ...
- SHA-256 简介及 C# 和 js 实现【加密知多少系列】
〇.简介 SHA-256 是 SHA-2 下细分出的一种算法.截止目前(2023-03)未出现"碰撞"案例,被视为是绝对安全的加密算法之一. SHA-2(安全散列算法 2:Secu ...
- Vue2依赖收集原理
观察者模式定义了对象间一对多的依赖关系.即被观察者状态发生变动时,所有依赖于它的观察者都会得到通知并自动更新.解决了主体对象和观察者之间功能的耦合. Vue中基于 Observer.Dep.Watch ...
- 正则表达式、datetime
1.正则表达式就是用来匹配字符串的 2.常用\d表示一个数字,\w表示数字或者字母,'.'表示任意字符 3.如果要匹配边长的字符串,使用*表示任意个字符,+表示至少一个字符,?表示0个或者1个字符,{ ...
- 如何使用sms-activate解决短信验证码问题
目录 前言 第一步:注册sms-activate 第二步:找到我们需要的服务 第三步:使用服务 前言 最近有许多小伙伴私信我,由于他们的工作需要让我安利一款接码工具供他们使用,于是我在调研各大接码平台 ...
- python移动同名文件
import os import shutil def split_name(file): file_name, _ = file.split('.') return file_name def mo ...
- 从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(二)
传送门:从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(一) 一.设置Swagger页面为首页--开发环境 我们虽然可以在输入 /swagger 后顺利的访问 ...