一、使用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。