最近在研究spring事务管理器的一些东西偶然在知乎上看到一篇文章
链接如下 https://www.zhihu.com/question/36948563
其中有一段话:
Spring事务处理逻辑是以切面的方式织入到业务(代理)对象中的。如果一个业务对象中两个方法(a,b)都配置了事务逻辑,如果在业务对象中方法a中直接调用了方法b,则这只是简单的方法级别调用,方法b上面的事务根本就在本次调用中感知不到。所以场景1,在调用了业务(代理)对象的a方法,a方法在调用b方法时抛出了异常,而且你在a方法体内catch了这个异常,对于调用者来说,a方法调用是正常的。场景2,你调用了业务(代理)对象的b方法,但是在调用处catch了异常,代理对象b方法的异常已经抛给了事务切面,事务已经回滚啦。如果你想在a方法中保证b方法的事务性,则在方法a中必须要获得业务(代理)对象,你可以在配置中添加
- <!-- 开启暴露Aop代理到ThreadLocal支持 -->
- <aop:aspectj-autoproxy expose-proxy="true"/>
- 在使用该标签时 需要在aop:config标签中添加 proxy-target-class="true" 否则会类型转换错误
- 具体看http://www.cnblogs.com/xing901022/p/4264172.html
然后通过Service service = (Service) AopContext.currentProxy();获取代理类 调用代理类的方法
Java动态代理主要涉及到两个类:
- InvocationHandler:该接口中仅定义了一个Object : invoke(Object proxy, Method method, Object[] args);参数proxy指代理类,method表示被代理的方法,args为method中的参数数组,返回值Object为代理实例的方法调用返回的值。这个抽象方法在代理类中动态实现。
- Proxy:所有动态代理类的父类,提供用于创建动态代理类和实例的静态方法。
所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
于是我用写了个小程序验证了下是否真的如此:
代码如下:
UserService.java
public interface UserService
{
public void add();
public void select();
}
UserServiceImpl.java public class UserServiceImpl implements UserService
{
public UserServiceImpl()
{
// TODO Auto-generated constructor stub
}
@Override
public void add()
{
System.out.println("add");
}
public void delete()
{
System.out.println("delete");
}
@Override
public void select()
{
add();
System.out.println("select");
}
}
JDK动态代理代理类
实现invocationHandler接口
//obj为实际需要去代理的类 在这里是UserServiceImpl类的实例
ServiceProxy.java
public class ServiceProxy implements InvocationHandler
{
private Object obj;
public ServiceProxy(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("事物开始");
//执行方法
Object result=method.invoke(obj, args);
System.out.println("事物结束");
return result;
}
}
测试类ProxyTest.java
public class ProxyTest
{
public ProxyTest()
{
// TODO Auto-generated constructor stub
}
public static void main(String[] args){
UserServiceImpl u = new UserServiceImpl();
ServiceProxy proxy = new ServiceProxy(u);
UserService service = (UserService) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),u.getClass().getInterfaces() , proxy);
service.add();
System.out.println("-------------");
service.select();
}
}
实际输出如下: 事物开始
add
事物结束
-------------
事物开始
add
select
事物结束
select方法中的add方法并没有执行代理方法 可见 那段话的确是正确的