自定义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 = "dataSource")@ConditionalOnMissingBeanpublic 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")@ConditionalOnMissingBeanpublic 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-dropCustom Conditions
除了使用@Condition** 之外,我們還可以繼承SpringBootCondition來實現自定義的condition。 如下所示:
public class HibernateCondition extends SpringBootCondition {private static String[] CLASS_NAMES= { "org.hibernate.ejb.HibernateEntityManager","org.hibernate.jpa.HibernateEntityManager" };@Overridepublic 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 {@Autowiredprivate MyUserRepository userRepository;@Testpublic 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
更多精彩內容且看:
- 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
- java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程
更多教程請參考 flydean的博客
總結
以上是生活随笔為你收集整理的自定义spring boot的自动配置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot @EnableA
- 下一篇: 在Spring Boot中配置web a