自定义spring boot的自动配置

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 自定义spring boot的自动配置

文章目录



自定义spring boot的自动配置


上篇文章我们讲了spring boot中自动配置的深刻含义和内部结构,这篇文章我们讲一下怎么写出一个自己的自动配置。为了方便和通用起见,这篇文章将会实现一个mysql数据源的自动配置。


添加Maven依赖


我们需要添加mysql和jpa的数据源:


<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
    </dependencies>


创建自定义 Auto-Configuration


我们知道 Auto-Configuration实际上就是一种配置好的@Configuration,所以我们需要创建一个MySQL 的@Configuration, 如下:


@Configuration
public class MySQLAutoconfiguration {
}


下一步就是将这个配置类注册到resources下面的/META-INF/spring.factories作为org.springframework.boot.autoconfigure.EnableAutoConfiguration的一个实现:


org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.flydean.config.MySQLAutoconfiguration


如果我们希望自定义的@Configuration拥有最高的优先级,我们可以添加@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 如下所示:


@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class MySQLAutoconfiguration {
}


注意, 自动配置的bean只有在该bean没有在应用程序中配置的时候才会自动被配置。如果应用程序中已经配置了该bean,则自动配置的bean会被覆盖。


添加Class Conditions


我们的mysqlConfig只有在DataSource这个类存在的时候才会被自动配置。则可以使用@ConditionalOnClass。 如果某个类不存在的时候生效则可以使用

@ConditionalOnMissingClass。


@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(DataSource.class)
public class MySQLAutoconfiguration {
}


添加 bean Conditions


如果我们需要的不是类而是bean的实例,则可以使用@ConditionalOnBean 和 @ConditionalOnMissingBean。


在本例中,我们希望当dataSource的bean存在的时候实例化一个LocalContainerEntityManagerFactoryBean:


@Bean
    @ConditionalOnBean(name = "dataSource")
    @ConditionalOnMissingBean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em
                = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("com.flydean.config.example");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        if (additionalProperties() != null) {
            em.setJpaProperties(additionalProperties());
        }
        return em;
    }


同样的,我们可以定义一个transactionManager, 只有当JpaTransactionManager不存在的时候才创建:


@Bean
@ConditionalOnMissingBean(type = "JpaTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}


Property Conditions


如果我们想在Spring配置文件中的某个属性存在的情况下实例化bean,则可以使用@ConditionalOnProperty。 首先我们需要加载这个Spring的配置文件:


@PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
    //...
}


我们希望属性文件里usemysql=local的时候创建一个DataSource, 则可以这样写:


@Bean
    @ConditionalOnProperty(
            name = "usemysql",
            havingValue = "local")
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true");
        dataSource.setUsername("mysqluser");
        dataSource.setPassword("mysqlpass");
        return dataSource;
    }


Resource Conditions


当我们需要根据resource文件是否存在来实例化bean的时候,可以使用@ConditionalOnResource 。


@ConditionalOnResource(
            resources = "classpath:mysql.properties")
    @Conditional(HibernateCondition.class)
    Properties additionalProperties() {
        Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.hbm2ddl.auto",
                env.getProperty("mysql-hibernate.hbm2ddl.auto"));
        hibernateProperties.setProperty("hibernate.dialect",
                env.getProperty("mysql-hibernate.dialect"));
        hibernateProperties.setProperty("hibernate.show_sql",
                env.getProperty("mysql-hibernate.show_sql") != null
                        ? env.getProperty("mysql-hibernate.show_sql") : "false");
        return hibernateProperties;
    }


我们需要在mysql.properties添加相应的配置:


mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=create-drop


Custom Conditions


除了使用@Condition** 之外,我们还可以继承SpringBootCondition来实现自定义的condition。 如下所示:


public class HibernateCondition extends SpringBootCondition {
    private static String[] CLASS_NAMES
            = { "org.hibernate.ejb.HibernateEntityManager",
            "org.hibernate.jpa.HibernateEntityManager" };
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context,
                                            AnnotatedTypeMetadata metadata) {
        ConditionMessage.Builder message
                = ConditionMessage.forCondition("Hibernate");
        return Arrays.stream(CLASS_NAMES)
                .filter(className -> ClassUtils.isPresent(className, context.getClassLoader()))
                .map(className -> ConditionOutcome
                        .match(message.found("class")
                                .items(ConditionMessage.Style.NORMAL, className)))
                .findAny()
                .orElseGet(() -> ConditionOutcome
                        .noMatch(message.didNotFind("class", "classes")
                                .items(ConditionMessage.Style.NORMAL, Arrays.asList(CLASS_NAMES))));
    }
}


测试


接下来我们可以测试了:


@RunWith(SpringRunner.class)
@SpringBootTest(
        classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
        basePackages = { "com.flydean.repository" })
public class AutoconfigurationTest {
    @Autowired
    private MyUserRepository userRepository;
    @Test
    public void whenSaveUser_thenOk() {
        MyUser user = new MyUser("user@email.com");
        userRepository.save(user);
    }
}


这里我们因为没有自定义dataSource所以会自动使用自动配置里面的mysql数据源。


停止自动配置


如果我们不想使用刚刚创建的自动配置该怎么做呢?在@SpringBootApplication中exclude MySQLAutoconfiguration.class即可:


@SpringBootApplication(exclude={MySQLAutoconfiguration.class})


本文的例子可以参考https://github.com/ddean2009/learn-springboot2/tree/master/springboot-custom-autoconfig

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
14天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
140 73
|
1天前
|
JavaScript Java 程序员
SpringBoot自动配置及自定义Starter
Java程序员依赖Spring框架简化开发,但复杂的配置文件增加了负担。SpringBoot以“约定大于配置”理念简化了这一过程,通过引入各种Starter并加载默认配置,几乎做到开箱即用。
34 10
SpringBoot自动配置及自定义Starter
|
15天前
|
XML Java 数据格式
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
本文介绍了在使用Spring框架时,如何通过创建`applicationContext.xml`配置文件来管理对象。首先,在resources目录下新建XML配置文件,并通过IDEA自动生成部分配置。为完善配置,特别是添加AOP支持,可以通过IDEA的Live Templates功能自定义XML模板。具体步骤包括:连续按两次Shift搜索Live Templates,配置模板内容,输入特定前缀(如spring)并按Tab键即可快速生成完整的Spring配置文件。这样可以大大提高开发效率,减少重复工作。
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
|
15天前
|
Java Maven Spring
SpringBoot配置跨模块扫描问题解决方案
在分布式项目中,使用Maven进行多模块开发时,某些模块(如xxx-common)没有启动类。如何将这些模块中的类注册为Spring管理的Bean对象?本文通过案例分析,介绍了两种解决方案:常规方案是通过`@SpringBootApplication(scanBasePackages)`指定扫描路径;推荐方案是保持各模块包结构一致(如com.xxx),利用SpringBoot默认扫描规则自动识别其他模块中的组件,简化配置。
SpringBoot配置跨模块扫描问题解决方案
|
15天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
14天前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
14天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
14天前
|
Java Spring
【Spring配置】创建yml文件和properties或yml文件没有绿叶
本文主要针对,一个项目中怎么创建yml和properties两种不同文件,进行配置,和启动类没有绿叶标识进行解决。
|
22天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
77 14
|
20天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
56 6
下一篇
开通oss服务