一、使用JTA的分布式事務
通過使用Atomikos或Bitronix嵌入式事務管理器,Spring Boot支持跨多個XA資源的分布式JTA事務。在部署到適當的Java EE應用服務器時,也支持JTA事務。
當檢測到JTA環境時,Spring的JtaTransactionManager用於管理事務。自動配置的JMS、數據源和JPA bean被升級為支持XA事務。您可以使用標准的Spring術語,例如@Transactional,來參與分布式事務。如果您在JTA環境中,仍然希望使用本地事務,那么可以設置spring.jta.enabled屬性為false以禁用JTA自動配置。
1.使用Atomikos事務管理器
Atomikos是一個流行的開源事務管理器,可以嵌入到Spring啟動應用程序中。您可以使用spring-boot-starter-jta-atomikos starter來導入適當的Atomikos庫。Spring Boot自動配置Atomikos,並確保將適當的依賴設置應用於Spring bean,以實現正確的啟動和關閉順序。
默認情況下,Atomikos事務日志被寫入應用程序的主目錄(應用程序jar文件所在的目錄)中的transaction-logs目錄。您可以通過在application.properties設置spring.jta.log-dir來定制此目錄的位置。屬性spring.jta.atomikos.properties可以用來定制Atomikos UserTransactionServiceImp。有關完整的詳細信息,請參閱AtomikosProperties Javadoc。
注:為了確保多個事務管理器可以安全地協調相同的資源管理器,每個Atomikos實例必須配置一個惟一的ID。為了確保生產中的唯一性,您應該配置spring.jta.transaction-manager-id對於應用程序的每個實例不同的值。
2.使用Bitronix事務管理器
Bitronix是一個流行的開源JTA事務管理器實現。您可以使用spring-boot-starter-jta-bitronix starter將適當的Bitronix依賴項添加到項目中。與Atomikos一樣,Spring Boot會自動配置Bitronix並對bean進行后處理,以確保啟動和關閉順序正確。
默認情況下,Bitronix事務日志文件(btm和part2.btm)被寫入應用程序主目錄中的事務日志目錄。您可以通過設置spring.jta來定制此目錄的位置。log dir屬性。屬性從spring.jta.bitronix開始。屬性也綁定到bitronix.tm。配置bean,允許完全自定義。有關詳細信息,請參閱Bitronix文檔。
注:為了確保多個事務管理器可以安全地協調相同的資源管理器,每個Bitronix實例必須配置一個惟一的ID。為了確保生產中的唯一性,您應該配置spring.jta.transaction-manager-id對於應用程序的每個實例不同的值。
3.使用Java EE托管事務管理器
如果將Spring啟動應用程序打包為war或ear文件並將其部署到Java EE應用服務器,則可以使用應用服務器的內置事務管理器。Spring Boot試圖通過查看常見的JNDI位置(java:comp/UserTransaction、java:comp/TransactionManager等)來自動配置事務管理器。如果使用應用服務器提供的事務服務,通常還需要確保所有資源都由服務器管理並通過JNDI公開。Spring Boot試圖通過在JNDI路徑(java:/JmsXA或java:/XAConnectionFactory)上查找ConnectionFactory來自動配置JMS,您可以使用Spring .datasource.jndi-name屬性來配置您的數據源。
4.混合XA和非XA JMS連接
在使用JTA時,主JMS ConnectionFactory bean是支持xa的,並參與分布式事務。在某些情況下,您可能希望使用非xa ConnectionFactory來處理某些JMS消息。例如,您的JMS處理邏輯可能需要比XA超時更長的時間。
如果希望使用非xa ConnectionFactory,可以注入nonXaJmsConnectionFactory bean,而不是@Primary jmsConnectionFactory bean。為了保持一致性,jmsConnectionFactory bean也是通過使用bean別名xaJmsConnectionFactory提供的。
下面的例子展示了如何注入ConnectionFactory實例:
// Inject the primary (XA aware) ConnectionFactory @Autowired private ConnectionFactory defaultConnectionFactory; // Inject the XA aware ConnectionFactory (uses the alias and injects the same as above) @Autowired @Qualifier("xaJmsConnectionFactory") private ConnectionFactory xaConnectionFactory; // Inject the non-XA aware ConnectionFactory @Autowired @Qualifier("nonXaJmsConnectionFactory") private ConnectionFactory nonXaConnectionFactory;
5.支持可選的嵌入式事務管理器
XAConnectionFactoryWrapper和XADataSourceWrapper接口可用於支持其他嵌入式事務管理器。這些接口負責包裝XAConnectionFactory和XADataSource bean,並將它們作為常規的ConnectionFactory和DataSource bean公開,它們透明地注冊到分布式事務中。數據源和JMS自動配置使用JTA變體,前提是您在ApplicationContext中注冊了一個JtaTransactionManager bean和適當的XA包裝器bean。
BitronixXAConnectionFactoryWrapper和BitronixXADataSourceWrapper提供了如何編寫XA包裝器的好例子。
https://github.com/spring-projects/spring-boot/blob/v2.2.2.RELEASE/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapper.java 和https://github.com/spring-projects/spring-boot/blob/v2.2.2.RELEASE/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapper.java
二、Hazelcast
如果Hazelcast位於類路徑中,並且找到了合適的配置,Spring Boot將自動配置一個HazelcastInstance,您可以將其注入到您的應用程序中。
如果你定義了com.hazelcast.config.Config bean, Spring Boot使用它。如果您的配置定義了一個實例名,Spring Boot將嘗試定位一個現有實例,而不是創建一個新實例。
您還可以通過配置指定Hazelcast配置文件,如下面的示例所示:
spring.hazelcast.config=classpath:config/my-hazelcast.xml
否則,Spring Boot將嘗試從默認位置(工作目錄或類路徑根目錄中的Hazelcast .xml,或相同位置的.yaml對等物)查找Hazelcast配置。我們還檢查了榛子醬。設置了配置系統屬性。有關詳細信息,請參閱Hazelcast文檔。
如果類路徑中存在hazelcast-client, Spring Boot首先嘗試通過檢查以下配置選項來創建客戶端:
- 存在com.hazelcast.client.config.ClientConfig實例bean
- 通過spring.hazelcast.config定義一個配置文件
- 存在hazelcast.client.config系統屬性
- 在工作路徑或根路徑下有hazelcast-client.xml文件
- 在工作路徑或根路徑下有hazelcast-client.yaml文件
Spring Boot還提供了對Hazelcast的顯式緩存支持。如果啟用了緩存,HazelcastInstance將自動包裝在CacheManager實現中。
三、Quartz調度器
Spring Boot為使用Quartz調度器提供了一些便利,包括spring-boot-starter-quartz “Starter”。如果Quartz可用,則自動配置調度器(通過SchedulerFactoryBean抽象)。
以下類型的bean會自動拾取並與調度器關聯:
- JobDetail:定義一個特殊的任務。使用JobBuilder API構建JobDetail實例。
- Calendar
- Trigger:定義何時觸發特定任務。
默認情況下,使用內存中的JobStore。但是,如果應用程序中有數據源bean可用,並且相應的配置了spring.quartz.job-store-typez,則可以配置基於jdbc的存儲。如下例所示:
spring.quartz.job-store-type=jdbc
當使用JDBC store時,模式可以在啟動時初始化,如下面的例子所示:
spring.quartz.jdbc.initialize-schema=always
注:默認情況下,使用Quartz庫提供的標准腳本檢測和初始化數據庫。這些腳本刪除現有的表,在每次重新啟動時刪除所有觸發器。還可以通過設置spring.quartz.jdbc.schema來提供自定義腳本。
要讓Quartz使用應用程序的主數據源之外的數據源,聲明一個數據源bean,用@QuartzDataSource注釋它的@Bean方法。這樣做可以確保SchedulerFactoryBean和模式初始化都使用特定於quartz的數據源。
默認情況下,配置創建的作業不會覆蓋從持久作業存儲區讀取的已注冊作業。要啟用覆蓋現有作業定義,請設置spring.quartz.overwrite-existing-jobs屬性。
可以使用spring定制Quartz調度器配置。quartz屬性和SchedulerFactoryBeanCustomizer bean,它們允許程序化的SchedulerFactoryBean自定義。可以使用spring.quartz.properties.*定制高級石英配置屬性。
具體來說,Executor bean與調度器沒有關聯,因為Quartz提供了一種通過spring.quartz.properties配置調度器的方法。如果需要自定義任務執行器,請考慮實現SchedulerFactoryBeanCustomizer。
Jobs可以定義setter來注入數據映射屬性。常規的bean也可以通過類似的方式注入,如下面的例子所示:
public class SampleJob extends QuartzJobBean { private MyService myService; private String name; // Inject "MyService" bean public void setMyService(MyService myService) { ... } // Inject the "name" job data property public void setName(String name) { ... } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { ... } }
四、任務執行和調度
在上下文中沒有Executor bean的情況下,Spring Boot會自動配置ThreadPoolTaskExecutor,並使用合理的默認值,這些默認值可以自動關聯到異步任務執行(@EnableAsync)和Spring MVC異步請求處理。
如果您已經在上下文中定義了一個自定義執行器,那么常規任務執行(即@EnableAsync)將透明地使用它,但是Spring MVC支持將不會被配置,因為它需要一個AsyncTaskExecutor實現(名為applicationTaskExecutor)。根據您的目標安排,您可以將執行程序更改為ThreadPoolTaskExecutor,或者定義一個ThreadPoolTaskExecutor和一個包裝自定義執行程序的AsyncConfigurer。
自動配置的TaskExecutorBuilder允許您輕松地創建實例,這些實例再現了默認情況下自動配置的功能。
線程池使用8個核心線程,這些線程可以根據負載大小進行增減。可以使用spring.task.execution命名空間對這些默認設置進行微調。如下例所示:
spring.task.execution.pool.max-size=16 spring.task.execution.pool.queue-capacity=100 spring.task.execution.pool.keep-alive=10s
這將線程池更改為使用有界隊列,以便當隊列滿時(100個任務),線程池增加到最多16個線程。當線程空閑10秒(而不是默認的60秒)時,池的收縮會更有侵略性。
如果需要將ThreadPoolTaskScheduler與計划的任務執行相關聯,也可以自動配置ThreadPoolTaskScheduler (@ enableschscheduling)。線程池默認使用一個線程,可以使用spring.task對這些設置進行微調。調度名稱空間。
如果需要創建自定義執行器或調度器,則可以在上下文中使用TaskExecutorBuilder bean和TaskSchedulerBuilder bean。