加入收藏 | 设为首页 | 会员中心 | 我要投稿 北几岛 (https://www.beijidao.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

自定义spring boot的自动配置

发布时间:2021-05-21 08:16:10 所属栏目:大数据 来源: https://www.jb51.cc
导读:文章目录 添加Maven依赖 创建自定义 Auto-Configuration 添加Class Conditions 添加 bean Conditions Property Conditions Resource Conditions Custom Conditions 测试 停止自动配置 自定义spring boot的自动配置 上篇文章我们讲了spring boot中自动配置的

文章目录

    • 添加Maven依赖
    • 创建自定义 Auto-Configuration
      • 添加Class Conditions
      • 添加 bean Conditions
      • Property Conditions
      • Resource Conditions
      • Custom Conditions
    • 测试
    • 停止自动配置

自定义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 = @H_82_301@"dataSource")
    @ConditionalOnMissingBean
    public LocalContainerEntityManagerfactorybean entityManagerFactory() {
        LocalContainerEntityManagerfactorybean em
                = new LocalContainerEntityManagerfactorybean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(@H_82_301@"com.flydean.config.example");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        if (additionalProperties() != null) {
            em.setJpaProperties(additionalProperties());
        }
        return em;
    }

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

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

Property Conditions

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

@PropertySource(@H_82_301@"classpath:MysqL.properties")
public class MysqLAutoconfiguration {
    //...
}

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

    @Bean
    @ConditionalOnProperty(
            name = @H_82_301@"useMysqL",
            havingValue = @H_82_301@"local")
    @ConditionalOnMissingBean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(@H_82_301@"com.MysqL.cj.jdbc.Driver");
        dataSource.setUrl(@H_82_301@"jdbc:MysqL://localhost:3306/myDb?createDatabaseIfNotExist=true");
        dataSource.setUsername(@H_82_301@"MysqLuser");
        dataSource.setPassword(@H_82_301@"MysqLpass");
        return dataSource;
    }

Resource Conditions

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

    @ConditionalOnResource(
            resources = @H_82_301@"classpath:MysqL.properties")
    @Conditional(HibernateCondition.class)
    Properties additionalProperties() {
        Properties hibernateProperties = new Properties();

        hibernateProperties.setProperty(@H_82_301@"hibernate.hbm2ddl.auto",
                env.getProperty(@H_82_301@"MysqL-hibernate.hbm2ddl.auto"));
        hibernateProperties.setProperty(@H_82_301@"hibernate.dialect",
                env.getProperty(@H_82_301@"MysqL-hibernate.dialect"));
        hibernateProperties.setProperty(@H_82_301@"hibernate.show_sql",
                env.getProperty(@H_82_301@"MysqL-hibernate.show_sql") != null
                        ? env.getProperty(@H_82_301@"MysqL-hibernate.show_sql") : @H_82_301@"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
            = { @H_82_301@"org.hibernate.ejb.HibernateEntityManager",
            @H_82_301@"org.hibernate.jpa.HibernateEntityManager" };

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context,
                                            AnnotatedTypeMetadata Metadata) {

        ConditionMessage.Builder message
                = ConditionMessage.forCondition(@H_82_301@"Hibernate");
        return Arrays.stream(CLASS_NAMES)
                .filter(className -> ClassUtils.isPresent(className, context.getClassLoader()))
                .map(className -> ConditionOutcome
                        .match(message.found(@H_82_301@"class")
                                .items(ConditionMessage.Style.NORMAL, className)))
                .findAny()
                .orElseGet(() -> ConditionOutcome
                        .noMatch(message.didNotFind(@H_82_301@"class", @H_82_301@"classes")
                                .items(ConditionMessage.Style.NORMAL, Arrays.asList(CLASS_NAMES))));
    }
}

测试

接下来我们可以测试了:

@RunWith(SpringRunner.class)
@SpringBootTest(
        classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
        basePackages = { @H_82_301@"com.flydean.repository" })
public class AutoconfigurationTest {

    @Autowired
    private MyUserRepository userRepository;

    @Test
    public void whenSaveUser_thenOk() {
        MyUser user = new MyUser(@H_82_301@"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

更多教程请参考 flydean的博客

(编辑:北几岛)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读