(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 来只启用 JdbcUserDAOMongoUserDAO 其中一个。

如果应用程序使用了 java -jar myapp.jar -DdbType = MySQL 启动,则启用 JdbcUserDAO,如果启动时使用了 java -jar myapp.jar -DdbType = MONGO,则启用 MongoUserDAO

假设我们有 UserDAO 接口,以下是 JdbcUserDAOMongoUserDAO 实现类:

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 条件性地配置 JdbcUserDAOMongoUserDAO 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} .jarorg.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的更多相关文章

  1. spring-boot autoConfiguration

    一, 第一个待注入类 public class CacheService { } public class LoggerService { } 方法一, 实现接口ImportSelectort pub ...

  2. 了解 Spring Boot AutoConfiguration

    原文:http://sivalabs.in/2016/03/how-springboot-autoconfiguration-magic/ 作者:Siva 译者:http://oopsguy.com ...

  3. spring boot 四大组件之Auto Configuration

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  4. springboot 自定义starter之AutoConfiguration【原】

    八.自定义starter AutoConfiguration: 1.这个场景需要使用到的依赖是什么? 没有特别依赖的配置 2.如何编写自动配置 @Configuration //指定这个类是一个配置类 ...

  5. SpringBoot四大神器之auto-configuration

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  6. SpringBoot使用AutoConfiguration自定义Starter

    https://segmentfault.com/a/1190000011433487

  7. 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 : ** ...

  8. Springboot搭建web项目

    最近因为项目需要接触了springboot,然后被其快速零配置的特点惊呆了.关于springboot相关的介绍我就不赘述了,大家自行百度google. 一.pom配置 首先,建立一个maven项目,修 ...

  9. SpringBoot前世今生

    序 本文主要讲述spring boot的由来,即其它诞生的背景,初衷,现状,及对未来的展望. 背景 在很早的年代,J2EE还是java企业级应用的王者规范,EJB风行其道.后来有一个叫Rod John ...

  10. SpringBoot常用配置简介

    SpringBoot常用配置简介 1. SpringBoot中几个常用的配置的简单介绍 一个简单的Spring.factories # Bootstrap components org.springf ...

随机推荐

  1. HDF格式遥感影像批量转为TIFF格式:ArcPy实现

      本文介绍基于Python中ArcPy模块,实现大量HDF格式栅格图像文件批量转换为TIFF格式的方法.   首先,来看看我们想要实现的需求.   在一个名为HDF的文件夹下,有五个子文件夹:每一个 ...

  2. JUC源码学习笔记8——ConcurrentHashMap源码分析1 如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移

    源码基于jdk1.8 这一片主要讲述ConcurrentHashMap如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移 系列文章目录和关于我 一丶ConcurrentHashMap概 ...

  3. 【JS基础】ES6模块系统

    export export 导出方式有两种,命名导出和默认导出. 命名导出还是默认导出都是都导出模块中内容的一种方式,可以混合使用. 个人理解:默认导出其实是导出了default别名变量. 一个模块只 ...

  4. 1.HVV介绍

    HVV介绍 1.护网职责划分 红队:打点人员.攻击人员.社工人员 蓝队:监控人员.研判人员.溯源人员 2.护网需要具备的技能 红队: 外围打点能力.漏洞挖掘能力.漏洞分析能力.权限提升能力.权限维持能 ...

  5. Python最详细的Excel操作方式,

    为 什么要学会使用Excel在机器学习模型的建立中,不得不借助于Excel强大的统计分析能力,这个时候就牵涉到了如何将python直接处理得到的数据存入excel表格当中以及获取表格的数据进行分析,简 ...

  6. [操作系统]记一次未尽的三星 Galaxy A6s(SM-G6200)刷机过程

    给女王大人刷机,第一次刷机,很遗憾,遇到了三星的"锁三键"问题,没有搞成.记录一下这个过程所涉猎的一些刷机基本知识,不妨当作一次学习过程. 1 刷机过程 Step1 查看手机基本信 ...

  7. 9.springSecurity整合OAuth2结合Jwt实现单点登录

    1.总结:昨天主要是继续完善OAuth2配合将问题完成单点登录,昨天也应证了一个认证服务,两个客户端服务在登陆一次后可以访问两个客户端的页面,也算是完成了单点登录   2.具体实现 首先是使用java ...

  8. .NET中使用RabbitMQ总结

    目前业界使用较多的消息队列组件有RabbitMQ.ActiveMQ.MSMQ.kafka.zeroMQ等 之间的对比可以看这里 之前搭过ActiveMQ环境带源码 点击这里 后来发现RabbitMQ性 ...

  9. 多表查询和python操作mysql

    目录 多表查询的两种方法 方法1:连表操作 方法2:子查询 小知识点补充说明 可视化软件NaviCat 多表查询练习题 1.查询所有的课程的名称以及对应的任课老师姓名 2.查询平均成绩大于八十分的同学 ...

  10. 用 hexo 结合 github 从0到1开始搭建属于你的blog

    前言 github pages服务搭建博客的好处有: 全是静态文件,访问速度快: 免费方便,不用花一分钱就可以搭建一个自由的个人博客,不需要服务器不需要后台: 可以随意绑定自己的域名,不仔细看的话根本 ...