BestJaxXu

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
 

(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)

posted on   BestJaxXu  阅读(140)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
 
点击右上角即可分享
微信分享提示