SpringBoot学习(九)使用JTA的分布式事务、Hazelcast、Quartz调度器和任务执行和调度

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

 

posted on 2019-12-28 17:44  木西-Muxy  阅读(1811)  评论(0编辑  收藏  举报

导航