日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot AutoConfiguration魔术如何工作?

發布時間:2023/12/3 javascript 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot AutoConfiguration魔术如何工作? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在我以前的文章中, 為什么選擇SpringBoot? 我們已經研究了如何創建SpringBoot應用程序。 但是您可能會也可能不會了解幕后發生的事情。 您可能想了解SpringBoot自動配置背后的魔力。

但是在此之前,您應該了解Spring的@Conditional功能,所有SpringBoot的AutoConfiguration魔術賴以其基礎。

探索@Conditional的力量

在開發基于Spring的應用程序時,我們可能會遇到有條件地注冊bean的需求。

例如,您可能想在本地運行應用程序時注冊一個指向DEV數據庫的DataSource bean,而在生產環境中運行時則指向一個不同的PRODUCTION數據庫。

您可以將數據庫連接參數外部化為屬性文件,并使用適合于環境的文件。 但是,每當需要指向其他環境并構建應用程序時,都需要更改配置。

為了解決這個問題,Spring 3.1引入了Profiles的概念。 您可以注冊多個相同類型的bean,并將它們與一個或多個概要文件關聯。 當您運行該應用程序時,您可以激活所需的概要文件,并且僅與激活的概要文件關聯的bean將被注冊。

@Configuration public class AppConfig {@Bean@Profile("DEV")public DataSource devDataSource() {...}@Bean@Profile("PROD")public DataSource prodDataSource() {...} }

然后,您可以使用系統屬性-Dspring.profiles.active = DEV指定活動配置文件

這種方法適用于簡單的情況,例如基于激活的配置文件啟用或禁用bean注冊。 但是,如果您要基于某些條件邏輯來注冊bean,那么Profiles方法本身是不夠的。

為了為有條件地注冊Spring Bean提供更大的靈活性,Spring 4引入了@Conditional的概念。 通過使用@Conditional方法,您可以根據任意條件有條件地注冊bean。

例如,在以下情況下,您可能要注冊一個bean:

  • 一個特定的類存在于類路徑中
  • 某種類型的Spring bean尚未在ApplicationContext中注冊
  • 特定文件存在于某個位置
  • 在配置文件中配置特定的屬性值
  • 存在/不存在特定的系統屬性

這些僅是幾個示例,您可以具有所需的任何條件。

讓我們看一下Spring的@Conditional的工作原理。

假設我們有一個UserDAO接口,其中包含從數據存儲中獲取數據的方法。 我們UserDAO的接口即JdbcUserDAO兩種工具進行對話的MySQL數據庫和MongoUserDAO進行對話的MongoDB的 。

我們可能只想基于系統屬性dbType啟用JdbcUserDAO和MongoUserDAO之一。

如果使用java -jar myapp.jar -DdbType = MySQL啟動應用程序,則我們要啟用JdbcUserDAO ;否則,如果使用java -jar myapp.jar -DdbType = MONGO啟動應用程序, 則要啟用MongoUserDAO 。

假設我們有UserDAO接口和JdbcUserDAO , MongoUserDAO實現如下:

public interface UserDAO {List<String> getAllUserNames(); }public class JdbcUserDAO implements UserDAO {@Overridepublic List<String> getAllUserNames(){System.out.println("**** Getting usernames from RDBMS *****");return Arrays.asList("Siva","Prasad","Reddy");} }public class MongoUserDAO implements UserDAO {@Overridepublic List<String> getAllUserNames(){System.out.println("**** Getting usernames from MongoDB *****");return Arrays.asList("Bond","James","Bond");} }

我們可以實現條件MySQLDatabaseTypeCondition來檢查系統屬性dbType是否為“ MYSQL” ,如下所示:

public class MySQLDatabaseTypeCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata){String enabledDBType = System.getProperty("dbType");return (enabledDBType != null && enabledDBType.equalsIgnoreCase("MYSQL"));} }

我們可以實現條件MongoDBDatabaseTypeCondition來檢查系統屬性dbType是否為“ MONGODB ”,如下所示:

public class MongoDBDatabaseTypeCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata){String enabledDBType = System.getProperty("dbType");return (enabledDBType != null && enabledDBType.equalsIgnoreCase("MONGODB"));} }

現在,我們可以使用@Conditional有條件地配置JdbcUserDAO和MongoUserDAO 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將被注冊。

現在,我們已經看到了如何基于系統屬性有條件地注冊bean。

假設我們希望,注冊MongoUserDAO豆只有當MongoDB的 Java驅動程序類“com.mongodb.Server”可在類路徑中,如果不是我們想注冊JdbcUserDAO豆。

為此,我們可以創建條件來檢查MongoDB驅動程序類“ com.mongodb.Server”的存在與否,如下所示:

public class MongoDriverPresentsCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata metadata){try {Class.forName("com.mongodb.Server");return true;} catch (ClassNotFoundException e) {return false;}} }public class MongoDriverNotPresentsCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata){try {Class.forName("com.mongodb.Server");return false;} catch (ClassNotFoundException e) {return true;}} }

我們剛剛看到了如何根據類路徑中是否存在類來有條件地注冊bean。

如果僅在尚未注冊其他類型為UserDAO的 Spring Bean的情況下才想注冊MongoUserDAO Bean,該怎么辦?

我們可以創建一個條件來檢查是否存在某種特定類型的現有bean,如下所示:

public class UserDAOBeanNotPresentsCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata){UserDAO userDAO = conditionContext.getBeanFactory().getBean(UserDAO.class);return (userDAO == null);} }

如果僅在屬性占位符配置文件中設置屬性app.dbType = MONGO時才想注冊MongoUserDAO bean,該怎么辦 ?

我們可以如下實現該條件:

public class MongoDbTypePropertyCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext,AnnotatedTypeMetadata metadata){String dbType = conditionContext.getEnvironment().getProperty("app.dbType");return "MONGO".equalsIgnoreCase(dbType);} }

我們剛剛看到了如何實現各種類型的條件。 但是,還有使用注釋來實現條件的更優雅的方法。 除了為MYSQL和MongoDB創建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 {@Overridepublic 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));} }

現在,我們可以在bean定義上使用@DatabaseType批注,如下所示:

@Configuration @ComponentScan public class AppConfig {@DatabaseType("MYSQL")public UserDAO jdbcUserDAO(){return new JdbcUserDAO();}@Bean@DatabaseType("MONGO")public UserDAO mongoUserDAO(){return new MongoUserDAO();} }

在這里,我們從DatabaseType批注中獲取元數據,并對照System Property dbType值進行檢查,以確定是啟用還是禁用Bean注冊。

我們已經看到了很多示例,以了解如何使用@Conditional批注有條件地注冊bean。

SpringBoot廣泛使用@Conditional功能根據各種條件有條件地注冊bean。

您可以在spring-boot-autoconfigure- {version} .jar的 org.springframework.boot.autoconfigure包中找到SpringBoot使用的各種Condition實現。

現在,我們了解了SpringBoot如何使用@Conditional功能有條件地檢查是否注冊Bean。 但是究竟是什么觸發了自動配置機制呢?

這就是我們將在下一部分中討論的內容。

SpringBoot自動配置

SpringBoot自動配置魔術的關鍵是@EnableAutoConfiguration批注。 通常,我們使用@SpringBootApplication注釋應用程序入口點類,或者如果要自定義默認值,則可以使用以下注釋:

@Configuration @EnableAutoConfiguration @ComponentScan public class Application {}

@EnableAutoConfiguration批注通過掃描類路徑組件并注冊與各種條件匹配的bean來啟用Spring ApplicationContext的自動配置。

SpringBoot在spring-boot-autoconfigure- {version} .jar中提供了各種AutoConfiguration類,這些類負責注冊各種組件。

通常, AutoConfiguration類使用@Configuration注釋,以將其標記為Spring配置類,并使用@EnableConfigurationProperties注釋,以綁定定制屬性和一個或多個條件Bean注冊方法。

例如,考慮org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration類。

@Configuration @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @EnableConfigurationProperties(DataSourceProperties.class) @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class }) public class DataSourceAutoConfiguration {......@Conditional(DataSourceAutoConfiguration.EmbeddedDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import(EmbeddedDataSourceConfiguration.class)protected static class EmbeddedConfiguration {}@Configuration@ConditionalOnMissingBean(DataSourceInitializer.class)protected static class DataSourceInitializerConfiguration {@Beanpublic DataSourceInitializer dataSourceInitializer() {return new DataSourceInitializer();}}@Conditional(DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })protected static class NonEmbeddedConfiguration {@Autowiredprivate DataSourceProperties properties;@Bean@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)public DataSource dataSource() {DataSourceBuilder factory = DataSourceBuilder.create(this.properties.getClassLoader()).driverClassName(this.properties.getDriverClassName()).url(this.properties.getUrl()).username(this.properties.getUsername()).password(this.properties.getPassword());if (this.properties.getType() != null) {factory.type(this.properties.getType());}return factory.build();}}......@Configuration@ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")@ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")@Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)@ConditionalOnMissingBean(name = "dataSourceMBean")protected static class TomcatDataSourceJmxConfiguration {@Beanpublic Object dataSourceMBean(DataSource dataSource) {........}}...... }

此處, DataSourceAutoConfiguration帶有@ConditionalOnClass({DataSource.class,EmbeddedDatabaseType.class})注釋,這意味著僅當在類路徑上有DataSource.class和EmbeddedDatabaseType.class類可用時,才會考慮在DataSourceAutoConfiguration中對bean進行自動配置。

該類還帶有@EnableConfigurationProperties(DataSourceProperties.class)批注,該啟用了自動將application.properties中的屬性綁定到DataSourceProperties類的屬性的功能。

@ConfigurationProperties(prefix = DataSourceProperties.PREFIX) public class DataSourceProperties implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {public static final String PREFIX = "spring.datasource";......private String driverClassName;private String url;private String username;private String password;...//setters and getters }

使用此配置,所有以spring.datasource。*開頭的屬性都將自動綁定到DataSourceProperties對象。

spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=secret spring.datasource.driver-class-name=com.mysql.jdbc.Driver

您還可以看到一些內部類和bean定義方法,這些內部類和bean定義方法用SpringBoot的條件注釋(例如@ ConditionalOnMissingBean,@ ConditionalOnClass和@ConditionalOnProperty等)進行注釋。

僅當這些條件匹配時,這些Bean定義才會在ApplicationContext中注冊。

您還可以在spring-boot-autoconfigure- {version} .jar中探索許多其他AutoConfiguration類,例如

  • org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration
  • org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
  • org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
  • org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration等。

我希望您現在通過使用各種AutoConfiration類以及@Conditional功能來了解SpringBoot自動配置的工作方式。

翻譯自: https://www.javacodegeeks.com/2016/03/springboot-autoconfiguration-magic-works.html

總結

以上是生活随笔為你收集整理的SpringBoot AutoConfiguration魔术如何工作?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。