Spring框架-mf116834

概述

因为早期的j2ee标准太复杂了,所以大佬搞出了spring。

spring和现代化的j2ee(jakartaEE)是互补的关系。

spring没有拥抱jakartaEE平台的标准,而是整合jakataEE平台个别好用的单独的规范,是个老6。

核心技术

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)。看起来不重要。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值