您的位置:首页 > 编程语言 > Java开发

JDK动态代理干了什么事情?为什么我的事务会不起效?spring的事务到底应该怎么使用?原理是什么?

2013-10-16 11:58 866 查看
JDK动态代理剖析:
//接口
public interface HelloInterface extends Serializable {
public String hello(String name);
public String bye(String name);
}
//实现类
public class HelloInterfaceImpl implements HelloInterface {
@Override
public String hello(String name) {
return "你好" + name;
}
@Override
public String bye(String name) {
hello(name);
return "Bye " + name;
}
}
//方法拦截
public class HelloInterceptor implements InvocationHandler {
private HelloInterface helloInterface;
public HelloInterceptor(HelloInterface helloInterface) {
this.helloInterface = helloInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("拦截到方法:" + method.getName() + ",参数:" + args[0]);
return method.invoke(helloInterface, args);
}
}
//产生代理并测试
HelloInterface helloInterface = new HelloInterfaceImpl();
HelloInterceptor helloInterceptor = new HelloInterceptor(helloInterface);
HelloInterface helloInterfaceProxy = (HelloInterface) Proxy.newProxyInstance(
helloInterface.getClass().getClassLoader(),
helloInterface.getClass().getInterfaces(),
helloInterceptor);
helloInterfaceProxy.bye("张三");
输出结果:
拦截到方法:bye,参数:张三
注意:调用了方法bye,bye又调用了hello,但只拦截到了bye方法,没有拦截到bye又调用的hello方法
解释这个原因前先看看这个产生的代理对象:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import prox.HelloInterface;
public final class $Proxy0 extends Proxy
implements HelloInterface
{
private static Method m3;
private static Method m1;
private static Method m4;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final String bye(String paramString)
throws
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramString });
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String hello(String paramString)
throws
{
try
{
return (String)this.h.invoke(this, m4, new Object[] { paramString });
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m3 = Class.forName("prox.HelloInterface").getMethod("bye", new Class[] { Class.forName("java.lang.String") });
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m4 = Class.forName("prox.HelloInterface").getMethod("hello", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
该类是代理对象反编译后的源码,该类是JDK动态产生的,可以看到该类实现了HelloInterface,并通过如下代码得到了HelloInterface所有方法的反射
m3 = Class.forName("prox.HelloInterface").getMethod("bye", new Class[] { Class.forName("java.lang.String") });
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m4 = Class.forName("prox.HelloInterface").getMethod("hello", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
再看bye方法:
public final String bye(String paramString)
throws
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramString });
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
调用改方法实际上是调用HelloInterceptor(即:this.h,这个是在父类Proxy中通过protected InvocationHandler h;定义的)的invoke方法,
参数this即是代理对象本身,m3是bye方法的反射,new Object[] { paramString }为传入的参数,因此当调用helloInterface.bye("张三");时,
其实是执行HelloInterceptor的invoke方法,而在该方法:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("拦截到方法:" + method.getName() + ",参数:" + args[0]);
return method.invoke(helloInterface, args);
}
先输出,后用反射直接调用刚刚创建的实例 HelloInterface helloInterface = new HelloInterfaceImpl();的bye方法,很明显该实例是原始类,未做任何改变,
只不过调用的方式由显示调用变成了反射间接调用,不再与HelloInterceptor有关,其执行的不过是其内部的代码,所以bye方法再去调用hello方法并没有被拦截到,
同理,如果还有其它类似的方法被bye调用也不会被拦截到。
现在来回答事务的问题就简单了
spring中,JDK代理是由这个类产生的
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

它实现了InvocationHandler接口,当调用代理对象时会调用JdkDynamicAopProxy 的invoke方法,如果配置了事务,invoke方法会调用TransactionInterceptor来实现真正的事务处理,
现在就很明白了,如果我们有一个类BusinessService,它有两个方法methodA,methodB,如果methodA没有设置事务,methodB设置了事务,那么methodA调用了methodB,
methodB的事务也不会起效,因为虽然BusinessService被代理了,但当调用BusinessService的代理对象的methodA方法时会调用JdkDynamicAopProxy的invoke方法,

JdkDynamicAopProxy 发现mthodA没有事务就会略过TransactionInterceptor,进而调用原始的BusinessService的methodA方法,原始的BusinessService与JdkDynamicAopProxy 无关,
也就不会调用TransactionInterceptor了,所以不会起效;反之,如果先调用BusinessService的代理对象的 methodB,接着调用JdkDynamicAopProxy的invoke方法,

JdkDynamicAopProxy 发现mthodB有事务就会调用TransactionInterceptor进行事务处理,完毕后调用原始的BusinessService的methodB方法,如果methodB再掉其它方法,
这些方法都会有事务(因为事务对象(说白了就是jdbc的connnection)是存放在ThreadLocal中的,后续的方法如果设置了事务,调用时会判断事务是否在当前线程中存在,如果存在则直接使用,否则新开一个线程并存入TheadLocal中)
所以要保证事务有效可以有以下方法:
1.保证入口方法设置了事务
2.将事务方法封装到其他类中,在要使用的地方注入即可(这样保证了事务方法和调用方法属于不同的类,不同的代理)
3.要保证所有操作在一个事务中,请一定要在同一线程中执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐