概述
因为早期的j2ee标准太复杂了,所以大佬搞出了spring。
spring和现代化的j2ee(jakartaEE)是互补的关系。
spring没有拥抱jakartaEE平台的标准,而是整合jakataEE平台个别好用的单独的规范,是个老6。
-
Servlet API (JSR 340)
-
WebSocket API (JSR 356)
-
Concurrency Utilities (JSR 236)
-
JSON Binding API (JSR 367)
-
Bean Validation (JSR 303)
-
JPA (JSR 338)
-
JMS (JSR 914)
-
等等
核心技术
IoC容器
资源
校验,数据绑定,类型转换
spring表达式语言
面向切面编程
数据访问
事务管理
spring框架的事务支持模型的先进性
一般来说,企业级应用开发者对事务管理有两种选择:全局和本地事务。
全局事务:全局事务可以工作在多个事务资源上,典型的关系数据库和消息队列。应用服务器管理全局事务,通过JTA(非常的繁琐,不好用,特别是由于它的异常模型)。另外,JTA经常需要从JNDI上得到数据源,也就意味着使用JTA的时候还要连带着用JNDI。这种全局事务的使用方式限制了代码重用的可能性。JTA通常只有在应用服务器环境中才可以获得。
本地事务:本地事务关联具体的资源,例如,使用一个jdbc链接管理一个事务。本地事务一般更容易的使用,但是也有一个不好的地方,本地事务不能不能工作在多个事务资源上。
spring事务支持模型先进就先进在提供了一个一致的事务模型上(全局和本地一致)。
spring解决全局和本地事务不好的地方。能够让应用开发者使用一致的编程模型在任何的环境里面。代码写一次,可以在不同的环境不同的事务管理器中获益。spring框架提供声明式和编程式事务管理。大多数的用户倾向于使用声明式的事务模型,也是在大多数情况下被推荐的。
使用编程式事务,开发者能够使用spring框架提供的事务抽象,这些抽象能够运行在任何底层的事务基础设施上面。
使用更推荐的声明式事务,开发者能够写更少的代码甚至不需要写任何和事务管理有关的代码,因此,也就不依赖spring框架事务api或者任何其他事务的api。
理解spring框架事务抽象
spring事务抽象的关键是事务策略的概念。事务策略被TransactionManager接口所定义。具体点:
命令式事务管理被org.springframework.transaction.PlatformTransactionManager接口代表。
响应式事务管理被org.springframework.transaction.ReactiveTransactionManager接口代表。
PlatformTransactionManager
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
上面的接口主要是用来作服务提供者接口(service provider interface SPI),也可以在应用代码里面使用。平台事务管理接口因为是一个接口,所以很容易mock和打桩(就是测试)。平台事务管理器实现的存在方式就像其他在spring框架ioc容器中的bean一样。这样就算是使用JTA(JTA需要从应用服务器中使用JNDI寻找事务管理器,不好测试)也很好测试。
TransactionException能够从PlatformTransactionManager接口的任意一个方法扔出来。TransactionException继承自java.lang.RuntimeException。不需要强制检查异常,这个对写代码非常好用。一般来说,事务基础设施失败都是致命的,应用程序很难恢复过来。开发者可以也尝试捕捉这个异常,让程序从失败中恢复。
ReactiveTransactionManager
public interface ReactiveTransactionManager extends TransactionManager {
Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws TransactionException;
Mono<Void> commit(ReactiveTransaction status) throws TransactionException;
Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;
}
响应式编程才会用到。
TransactionDefinition接口
propagation:事务的传播,spring的事务是以方法为单位,方法内部可能还存在方法,事务的传播属性描述的就是外部方法对内部方法的作什么样的影响。事务由外部传播到内部,所以叫做传播。
isolation:就是acid中i(隔离级别)。
timeout:如果超过了这个时间,就回滚。
read-only:表示只读,表明不会作修改,也就不需要数据库在加各种锁。能够提升效率。
TransactionStatus接口
提供一个简单的方式控制事务执行和查询事务状态。
事务管理器的实现通常需要知道它们所工作的环境:JDBC,JTA, Hibernate, 等等。
下面展示如何定义一个本地PlatformTransactionManager的实现(JDBC)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
使用事务同步资源
高层次的同步方式
被推荐的方式是使用spring的高层次基于模板的持久化整合api(JdbcTemplate)或者使用拥有事务感知工厂bean或代理的原生ORM api(native ORM API)。这些事务感知的解决方案能够处理资源创建,重用,清理,资源的事务同步,和异常映射。因此用户访问代码不需要处理这些任务,而是可以把焦点聚焦在没有模板代码的持久化逻辑上面。
低层次的同步方式
DatasourceUtils -> JDBC
EntityManagerFactoryUtils -> JPA
SessionFactoryUtils -> Hibernate
Connection conn = DataSourceUtils.getConnection(dataSource);
低层次的api也会使用spring事务管理,好用的spring数据库异常。
高层次的低层次的不同点在于,低层次要多写一点代码。
事务和数据源是如何关联在一起的?
在非常低的层级上,存在TransactionAwareDataSourceProxy(能够感知事务的数据源代理)类。这个代理类的目标对象是DataSource,它包裹者目标数据源并且增加被spring管理的事务感知能力(数据源和spring事务关联起来了,增强数据源)。
声明式事务管理
理解spring框架的声明式事务实现
@Transactional
@EnableTransactionManagement
TransactionInterceptor
调用者,aop代理,事务增强器(重点,事务利用事务管理器创建,提交,回滚事务),定制的事务增强器,真正的方法。
回滚一个声明式事务的方式
在默认的配置中,扔一个运行时异常或者他的子类,触发回滚。
在默认的配置中,checked exception不会触发回滚。
可以配置哪些异常会触发回滚,包括受检异常和运行时异常。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
</tx:attributes>
</tx:advice>
public void resolvePosition() {
try {
// some business logic...
} catch (NoProductInStockException ex) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
最后编程的方式不推荐,侵入,紧密耦合spring框架。
为了不同的Bean提供不同的事务语义
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* x.y.service..*Service.*(..))"/>
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>
<!-- these two beans will be transactional... -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<bean id="barService" class="x.y.service.extras.SimpleBarService"/>
<!-- ... and these two beans won't -->
<bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->
<bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- other transaction infrastructure beans such as a TransactionManager omitted... -->
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* x.y.service..*Service.*(..))"/>
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>
<!-- these two beans will be transactional... -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<bean id="barService" class="x.y.service.extras.SimpleBarService"/>
<!-- ... and these two beans won't -->
<bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->
<bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- other transaction infrastructure beans such as a TransactionManager omitted... -->
</beans>
切点,增强器,增强。
<tx:advice/>设置
propagation是REQUIRED
isolation是DEFAULT
事务是读写
事务超时时间是底层事务系统默认值或者没有
任何运行时异常触发回滚,任何受检异常不会触发回调
编程式事务管理
spring框架提供了两种编程事务管理的方式
1,TransactionTemplate或者TransactionalOperator。
2,直接的TransactionManager实现
TransactionTemplate的使用
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method runs in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
平台事务管理器的使用
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// put your business logic here
} catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
编程事务和声明事务的选择
事务相关的事件
应用服务器标准整合
一般问题的解决
进一步的资源
数据访问对象支持
使用jdbc访问数据
使用对象关系映射访问数据
Servlet技术栈
整合
任务执行和调度
spring提供了执行和调度的抽象,TaskExecutor和TaskScheduler接口。
TaskExecutor抽象
为什么叫做executor,因为不保证底层的实现真的是一个线程池,也可以是单个线程,或者没有新开线程,使用同步的方式。
spring的抽象隐藏了javaSE和jakartaEE环境的区别。
TaskExecutor和java.util.concurrent.Executor差不多。TaskExecutor原来是为了给spring组件一个线程池抽象。例如ApplicationEventMulticaster,JMS的AbstractMessageListenerContainer,等等。如果我们自己的Bean需要线程池,也可以使用这个线抽象。
TaskExecutor类型
SyncTaskExecutor
没有多线程,就是使用调用者线程跑。用于测试,或者不需要多线程的地方。
SimpleAsyncTaskExecutor
简单也简陋,每一次调用就开启一个新的线程,但是支持配置并发上限。
ConcurrentTaskExecutor
这个实现是java.util.concurrent.Executor实例的一个适配者,暴露Executor配置参数作为bean属性。很少直接被使用,除非ThreadPoolTaskExecutor的灵活性不够用了,才用这个。
ThreadPoolTaskExecutor
这个实现最经常被使用,内部包裹了一个java.util.concurrent.ThreadPoolExecutor,并暴露bean属性用来配置。如果需要包裹其他的Executor,使用上面那个。
DefaultManagedTaskExecutor
JNDI-obtained (例如jakarta ee application server)。看起来不重要。