在Spring框架中,通过自定义的数据库事物拦截器,对所有的Service层的Bean中的*Save
和*Bc
方法进行事务控制。
主要涉及的技术有:
1. Spring AOP
2. annotation
3. component-scan
4. MethodInterceptor
5. NameMatchMethodPointcutAdvisor
6. BeanNameAutoProxyCreator
1.程序目录
project
\---src
\---main
\---java
| \---pers
| \---hanchao
| \---aop
| \---App.java
| \---AopController.java
| \---AopService.java
| \---AopRepository.java
| \---MyDbInterceptor.java
\---resources
\---spring-config
\---spring-aop.xml
2.App.java
package pers.hanchao.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* <p>在Spring框架中,通过自定义的数据库事物拦截器,对所有的Service层的Bean中的*Save和*Bc方法进行事务控制。</p>
* @author hanchao 2018/1/8 23:22
**/
public class App {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config/spring-aop.xml");
AopController aopController = (AopController) context.getBean("aopController");
//模拟数据库查询,不涉及事务控制
aopController.showMessage();
Thread.sleep(2000);//为了更好的打印控制台信息
//模拟数据库执行成功的情况
System.out.println("============================");
aopController.doSqlSuccess();
Thread.sleep(2000);
//模拟数据库执行中报错的情况
System.out.println("============================");
aopController.doSqlFailed();
}
}
3.AopController.java
package pers.hanchao.aop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class AopController {
@Autowired
private AopService aopService;
public void showMessage(){
this.aopService.showMessage();
}
public void doSqlSuccess(){
this.aopService.goodSave();
}
public void doSqlFailed() throws InterruptedException {
this.aopService.badBc();
}
}
4.AopService.java
package pers.hanchao.aop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AopService {
@Autowired
private AopRepository aopRepository;
public void showMessage() {
this.aopRepository.showMessage();
}
public void goodSave(){
this.aopRepository.doSqlSuccess();
}
public void badBc() throws InterruptedException {
this.aopRepository.doSqlFailed();
}
}
5.AopRepository.java
package pers.hanchao.aop;
import org.springframework.stereotype.Repository;
@Repository
public class AopRepository {
public void showMessage() {
System.out.println("No transaction!");
}
public void doSqlSuccess() {
System.out.println("Execute Sql success!");
}
public void doSqlFailed() throws InterruptedException {
System.out.println("Execute Sql failed!");
Thread.sleep(2000);
throw new NullPointerException();
}
}
6.MyDbInterceptor.java
package pers.hanchao.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* <p>自定义数据库事物拦截器(模拟)</p>
* @author hanchao 2018/1/8 23:22
**/
public class MyDbInterceptor implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
String beanName = methodInvocation.getThis().toString();
String method = methodInvocation.getMethod().getName();
System.out.println("[beanName:" + beanName + ",method:" + method + "]");
System.out.println("Transaction begin:conn.setAutoCommit(false);");
try{
Object result = methodInvocation.proceed();
System.out.println("Transaction commit:conn.commit();");
return result;
}catch (Exception e){
System.out.println("Transaction rollback:conn.rollback();");
e.printStackTrace();
return null;
}finally {
System.out.println("Db connection closed:ps1.close();conn.close();");
}
}
}
7.spring-aop.xml.xml
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解-->
<context:annotation-config/>
<!--开启@Component等注解的自动扫描-->
<context:component-scan base-package="pers.hanchao.*"/>
<!--自定义的db拦截器-->
<bean id="myDbInterceptor" class="pers.hanchao.aop.MyDbInterceptor"/>
<!--定义通过方法名称匹配的切入点指示器-->
<bean id="dbAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--映射一种BeanName-->
<!--<property name="mappedName" value="aopSave"/>-->
<!--映射多种BeanNames-->
<property name="mappedNames">
<list>
<value>*Save</value>
<value>*Bc</value>
</list>
</property>
<property name="advice" ref="myDbInterceptor"/>
</bean>
<!--定义通过Bean名称生成自动代理的创造器-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Service"/>
<property name="interceptorNames" value="dbAdvisor"/>
</bean>
</beans>
8.result
No transaction!
============================
[beanName:pers.hanchao.aop.AopService@6d763516,method:goodSave]
Transaction begin:conn.setAutoCommit(false);
Execute Sql success!
Transaction commit:conn.commit();
Db connection closed:ps1.close();conn.close();
============================
[beanName:pers.hanchao.aop.AopService@6d763516,method:badBc]
Transaction begin:conn.setAutoCommit(false);
Execute Sql failed!
java.lang.NullPointerException
Transaction rollback:conn.rollback();
at pers.hanchao.aop.AopRepository.doSqlFailed(AopRepository.java:18)
Db connection closed:ps1.close();conn.close();
at pers.hanchao.aop.AopService.badBc(AopService.java:20)
at pers.hanchao.aop.AopService$$FastClassBySpringCGLIB$$cc53b31d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:747)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at pers.hanchao.aop.MyDbInterceptor.invoke(MyDbInterceptor.java:19)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at pers.hanchao.aop.AopService$$EnhancerBySpringCGLIB$$b0199d73.badBc(<generated>)
at pers.hanchao.aop.AopController.doSqlFailed(AopController.java:20)
at pers.hanchao.aop.App.main(App.java:23)