更新時(shí)間:2022-05-16 10:10:28 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽3334次
簡(jiǎn)單地說(shuō),Spring Boot 自動(dòng)配置代表了一種基于類(lèi)路徑中存在的依賴(lài)項(xiàng)自動(dòng)配置 Spring 應(yīng)用程序的方法。
通過(guò)消除定義自動(dòng)配置類(lèi)中包含的某些 bean 的需要,這可以使開(kāi)發(fā)更快、更容易。
讓我們從我們需要的Maven依賴(lài)項(xiàng)開(kāi)始:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
最新版本的spring-boot-starter-data-jpa和mysql-connector-java可以從 Maven Central 下載。
要?jiǎng)?chuàng)建自定義自動(dòng)配置,我們需要?jiǎng)?chuàng)建一個(gè)注釋為@Configuration的類(lèi)并注冊(cè)它。
讓我們?yōu)镸ySQL數(shù)據(jù)源創(chuàng)建一個(gè)自定義配置:
@Configuration
public class MySQLAutoconfiguration {
//...
}
下一個(gè)強(qiáng)制性步驟是將類(lèi)注冊(cè)為自動(dòng)配置候選者,方法是在標(biāo)準(zhǔn)文件resources/META-INF/spring.factories中的鍵org.springframework.boot.autoconfigure.EnableAutoConfiguration下添加類(lèi)的名稱(chēng):
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baeldung.autoconfiguration.MySQLAutoconfiguration
如果我們希望我們的自動(dòng)配置類(lèi)優(yōu)先于其他自動(dòng)配置候選者,我們可以添加@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)注釋。
自動(dòng)配置是使用標(biāo)有@Conditional注釋的類(lèi)和 bean 設(shè)計(jì)的,以便可以替換自動(dòng)配置或其特定部分。
請(qǐng)注意,僅當(dāng)應(yīng)用程序中未定義自動(dòng)配置的 bean 時(shí),自動(dòng)配置才有效。如果你定義你的bean,那么默認(rèn)的將被覆蓋。
(1)班級(jí)條件
類(lèi)條件允許我們使用@ConditionalOnClass注解指定如果指定的類(lèi)存在,或者使用@ConditionalOnMissingClass注解不存在類(lèi),則將包含配置 bean。
讓我們指定只有當(dāng)DataSource類(lèi)存在時(shí)才會(huì)加載我們的MySQLConfiguration,在這種情況下,我們可以假設(shè)應(yīng)用程序?qū)⑹褂脭?shù)據(jù)庫(kù):
@Configuration
@ConditionalOnClass(DataSource.class)
public class MySQLAutoconfiguration {
//...
}
(2)bean條件
如果我們只想在指定的 bean 存在或不存在時(shí)才包含 bean,我們可以使用@ConditionalOnBean和@ConditionalOnMissingBean注釋。
為了舉例說(shuō)明這一點(diǎn),讓我們?cè)谂渲妙?lèi)中添加一個(gè)entityManagerFactory bean,并指定我們只希望在存在名為dataSource的 bean 并且尚未定義名為entityManagerFactory的 bean 時(shí)創(chuàng)建此 bean:
@Bean
@ConditionalOnBean(name = "dataSource")
@ConditionalOnMissingBean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.baeldung.autoconfiguration.example");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
if (additionalProperties() != null) {
em.setJpaProperties(additionalProperties());
}
return em;
}
讓我們還配置一個(gè)transactionManager bean,僅當(dāng)JpaTransactionManager類(lèi)型的 bean尚未定義時(shí)才會(huì)加載:
@Bean
@ConditionalOnMissingBean(type = "JpaTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
(3)條件
@ConditionalOnProperty注釋用于指定是否將基于 Spring Environment 屬性的存在和值來(lái)加載配置。
首先,讓我們?yōu)槲覀兊呐渲锰砑右粋€(gè)屬性源文件,該文件將確定從何處讀取屬性:
@PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
//...
}
我們可以配置將用于創(chuàng)建與數(shù)據(jù)庫(kù)的連接的主DataSource bean,只有在存在名為usemysql的屬性時(shí)才會(huì)加載它。
我們可以使用屬性havingValue來(lái)指定必須匹配的usemysql屬性的某些值。
如果usemysql屬性設(shè)置為local ,讓我們使用默認(rèn)值定義dataSource bean,該值連接到名為myDb的本地?cái)?shù)據(jù)庫(kù):
@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;
}
如果usemysql屬性設(shè)置為custom, dataSource bean將使用數(shù)據(jù)庫(kù) URL、用戶(hù)和密碼的自定義屬性值進(jìn)行配置:
@Bean(name = "dataSource")
@ConditionalOnProperty(
name = "usemysql",
havingValue = "custom")
@ConditionalOnMissingBean
public DataSource dataSource2() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl(env.getProperty("mysql.url"));
dataSource.setUsername(env.getProperty("mysql.user") != null
? env.getProperty("mysql.user") : "");
dataSource.setPassword(env.getProperty("mysql.pass") != null
? env.getProperty("mysql.pass") : "");
return dataSource;
}
mysql.properties文件將包含usemysql屬性:
usemysql=local
如果使用MySQLAutoconfiguration的應(yīng)用程序希望覆蓋默認(rèn)屬性,它所需要做的就是為mysql.url、mysql.user和mysql.pass屬性以及mysql.properties文件中的usemysql=custom行添加不同的值。
(4)資源條件
添加@ConditionalOnResource注解意味著只有在指定資源存在時(shí)才會(huì)加載配置。
讓我們定義一個(gè)名為additionalProperties()的方法,該方法將返回一個(gè)Properties對(duì)象,其中包含要由entityManagerFactory bean 使用的 Hibernate 特定屬性,僅當(dāng)資源文件mysql.properties存在時(shí):
@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;
}
我們可以將 Hibernate 特定的屬性添加到mysql.properties文件中:
mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=create-drop
(5)自定義條件
如果我們不想使用 Spring Boot 中可用的任何條件,我們還可以通過(guò)擴(kuò)展SpringBootCondition類(lèi)并覆蓋getMatchOutcome()方法來(lái)定義自定義條件。
讓我們?yōu)閍dditionalProperties()方法創(chuàng)建一個(gè)名為HibernateCondition的條件,該方法將驗(yàn)證HibernateEntityManager類(lèi)是否存在于類(lèi)路徑中:
static 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(Style.NORMAL, className)))
.findAny()
.orElseGet(() -> ConditionOutcome
.noMatch(message.didNotFind("class", "classes")
.items(Style.NORMAL, Arrays.asList(CLASS_NAMES))));
}
}
然后我們可以將條件添加到additionalProperties()方法中:
@Conditional(HibernateCondition.class)
Properties additionalProperties() {
//...
}
(6)申請(qǐng)條件
我們還可以通過(guò)添加@ConditionalOnWebApplication或@ConditionalOnNotWebApplication注釋來(lái)指定配置只能在 Web 上下文內(nèi)部/外部加載。
讓我們創(chuàng)建一個(gè)非常簡(jiǎn)單的示例來(lái)測(cè)試我們的自動(dòng)配置。我們將使用 Spring Data創(chuàng)建一個(gè)名為MyUser的實(shí)體類(lèi)和一個(gè)MyUserRepository接口:
@Entity
public class MyUser {
@Id
private String email;
// standard constructor, getters, setters
}
public interface MyUserRepository
extends JpaRepository<MyUser, String> { }
要啟用自動(dòng)配置,我們可以使用@SpringBootApplication或@EnableAutoConfiguration注釋之一:
@SpringBootApplication
public class AutoconfigurationApplication {
public static void main(String[] args) {
SpringApplication.run(AutoconfigurationApplication.class, args);
}
}
接下來(lái),讓我們編寫(xiě)一個(gè)保存MyUser實(shí)體的JUnit測(cè)試:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
basePackages = { "com.baeldung.autoconfiguration.example" })
public class AutoconfigurationTest {
@Autowired
private MyUserRepository userRepository;
@Test
public void whenSaveUser_thenOk() {
MyUser user = new MyUser("user@email.com");
userRepository.save(user);
}
}
由于我們尚未定義DataSource配置,因此應(yīng)用程序?qū)⑹褂梦覀儎?chuàng)建的自動(dòng)配置連接到名為myDb的MySQL數(shù)據(jù)庫(kù)。
連接字符串包含createDatabaseIfNotExist=true屬性,因此數(shù)據(jù)庫(kù)不需要存在。但是,需要?jiǎng)?chuàng)建用戶(hù)mysqluser或通過(guò)mysql.user屬性指定的用戶(hù)(如果存在)。
我們可以檢查應(yīng)用程序日志來(lái)查看MySQL數(shù)據(jù)源是否正在被使用:
web - 2017-04-12 00:01:33,956 [main] INFO o.s.j.d.DriverManagerDataSource - Loaded JDBC driver: com.mysql.cj.jdbc.Driver
如果我們想從加載中排除自動(dòng)配置,我們可以將帶有exclude或excludeName屬性的@EnableAutoConfiguration注解添加到配置類(lèi)中:
@Configuration
@EnableAutoConfiguration(
exclude={MySQLAutoconfiguration.class})
public class AutoconfigurationApplication {
//...
}
禁用特定自動(dòng)配置的另一個(gè)選項(xiàng)是設(shè)置spring.autoconfigure.exclude屬性:
spring.autoconfigure.exclude=com.baeldung.autoconfiguration.MySQLAutoconfiguration
以上就是關(guān)于“使用SpringBoot自定義配置文件”的介紹,如果大家想了解更多相關(guān)知識(shí),可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的SpringBoot教程,教程內(nèi)容從淺到深,通俗易懂,適合小白學(xué)習(xí),希望對(duì)大家能夠有所幫助。
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)