最近再项目中发现不少同事(包括自己)不太理解默认情况下的Spring事务的运行机制(主要是不理解AOP机制),导致随意使用事务注解.因此也在很多场景事务不生效。因此想从代理机制开始理一下整个Spring声明式事务的原理。
因为篇幅太长,分成三个部分:
(1).代理
(2).Spring的AOP
(3).Spring的事务
1.代理
通常,我们代码中处理核心的业务逻辑,还包含一些枝节性的代码和功能,比如日志记录、消息发送、安全、事务保证和监控等。
我们通常期望将这些枝节性的代码功能和我们的核心业务逻辑分离,减少业务功能和枝节功能的耦合。这时候我们就要使用代理来达到我们的目的。
代理的作用是:为其它对象提供一种代理以控制对这个对象的访问。简单理解就是中间的作用。代理一般涉及到三个角色:
(1).抽象角色:声明真实对象和代理对象的共同接口;
(2).代理角色:代理对象内部包含有真实角色的引用,从而可以操作真实角色,同时代理对象与真实对象有相同的接口,能在任何时候代替真实对象,同时代理对象可以在执行真实对 象前后加入特定的逻辑以实现功能的扩展;
(3).真实角色:代理角色所代表的真实对象,是我们最终要引用的对象;
1.1 代理模式
代理模式是一个经典的设计模式,介绍往上很多。
下面是一个最简单的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public interface IHello {
void hello();
}
public class HelloImpl implements IHello {
@Override
public void hello() {
System.out.println("HelloImpl: Hello World.");
}
}
public class HelloProxyImpl implements IHello {
private IHello inner;
public HelloProxyImpl(IHello inner) {
this.inner = inner;
}
@Override
public void hello() {
doSomethingBefore();
inner.hello();
doSomethingAfter();
}
private void doSomethingBefore() {
System.out.println("HelloProxyImpl: Before hello()...");
}
private void doSomethingAfter() {
System.out.println("HelloProxyImpl: After hello()...");
}
}
UML图大致如下:
从代码上我们可以看出,代理模式要求(这也是它的限制所在):
(1).代理类需要和被代理者一样实现相同的接口;
(2).代理类包含被代理者的引用;
1.2 Java动态代理
代理模式我们可以理解为一种静态代理,其问题是需要我们显示的为每个需要被代理的类实现一个代理类,即一个代理类只能为i一个被代理者做代理的功能。如果有上千个类需要代理,估计要骂娘了。
java动态代理正是为了解决这个问题。主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。我们只需要实现InvocationHandler接口,在实现invoke()方法的时候加上我们的代理逻辑。
一个简单的使用实例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* @author xiaobaoqiu Date: 16-3-10 Time: 下午6:18
*/
public class JavaDynamicProxy implements InvocationHandler {
/**
* 被代理者
*/
private Object inner;
/**
* 生成代理类
*/
public static Object generateProxy(Object inner) {
return Proxy.newProxyInstance(
inner.getClass().getClassLoader(),
inner.getClass().getInterfaces(),
new JavaDynamicProxy(inner));
}
private JavaDynamicProxy(Object inner) {
this.inner = inner;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomethingBefore();
Object result = method.invoke(inner, args);
doSomethingAfter();
return result;
}
private void doSomethingBefore() {
System.out.println("JavaDynamicProxy: Before...");
}
private void doSomethingAfter() {
System.out.println("JavaDynamicProxy: After...");
}
}
//使用
public static void main(String[] args) {
//被动态代理的IHello实例对象A
IHello helloA = new HelloImpl();
//生成对象A的动态代理
IHello helloAProxy = (IHello) JavaDynamicProxy.generateProxy(helloA);
helloAProxy.hello();
System.out.println("-------------------------------------------------");
// 一个JavaDynamicProxy可以一直使用
//被动态代理的IHello实例对象B
IHello helloB = new HelloWithLogImpl();
//生成对象B的动态代理
IHello helloBProxy = (IHello) JavaDynamicProxy.generateProxy(helloB);
helloBProxy.hello();
System.out.println("-------------------------------------------------");
//被动态代理对象IBye实例
IBye bye = new ByeImpl();
//生成IBye实例的动态代理
IBye byeProxy = (IBye) JavaDynamicProxy.generateProxy(bye);
byeProxy.bye();
}
JavaDynamicProxy.generateProxy的输出会是一个动态的代理类。debug信息如下,从debug信息我们大致知道,这个代理类的类名称为$Proxy0,内部包含一个属性名为h的属性,h指向的就是我们实现的InvocationHandler的类(这里即JavaDynamicProxy)的实例。
但是Java动态代理的限制是:
(1).被代理的类要求至少实现了一个Interface;
(2).被代理的类要求有public的构造函数(即没有显示的将其设置为private等);
(3).被代理的类要求不是final;
如下代理一个没有实现任何接口的类会报错
1
2
3
4
5
6
//没有实现任何interface的类使不能被动态代理的
System.out.println("-------------------------------------------------");
HelloWithoutInterface helloC = new HelloWithoutInterface();
//生成对象C的动态代理
HelloWithoutInterface helloCProxy = (HelloWithoutInterface) JavaDynamicProxy.generateProxy(helloC);
helloCProxy.hello();
错误信息如下:
1
2
3
4
5
6
7
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to proxy.javaProxy.HelloWithoutInterface
at proxy.javaProxy.JavaProxyMain.main(JavaProxyMain.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Java动态代理的机制是利用反射机制生成。具体代码可以debug,主要的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Proxy.java
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
...
Class<?> cl = getProxyClass0(loader, intfs); //生成代理类
...
return newInstance(cons, ih); // 生成代理类的实例
}
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
//生成代理类的主要逻辑在ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
//ProxyClassFactory的apply方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
...
String proxyPkg = null; // 生成代理类的包路径
...
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; //默认路径在com.sun.proxy下面
}
long num = nextUniqueNumber.getAndIncrement(); //代理类的序号, 我们熟悉的$Proxy0中的0
String proxyName = proxyPkg + proxyClassNamePrefix + num; //代理类的类名称
//使用ProxyGenerator生成代理类的字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
//生成代理类
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
}
//ProxyGenerator.generateProxyClass的代码太恶心的...
我们可以自己使用ProxyGenerator来生成代理类并将其字节码记录下来:
1
2
3
// 获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", ByeImpl.class.getInterfaces());
//将字节码写文件,建议写成.class文件
获取的字节码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.sample.IBye;
public final class $Proxy0 extends Proxy implements IBye {
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void bye() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("proxy.sample.IBye").getMethod("bye", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
从生成的类我们知道,代理类继承Proxy类(这就是为什么Proxy类内的InvocationHandler实例未protected)并实现我们需要的被代理者的Interface(比如这里的bye()方法),另外它只要一个接受一个InvocationHandler为参数的构造函数。当我们调用代理类的bye()方法时候,其实是调用我们实现的InvocationHandler(即上面的JavaDynamicProxy)的invoke()方法,在invoke()方法里面,我们实现了我的代理逻辑。
我们这里这个Demo的大致UML图如下:
参考:http://www.cnblogs.com/cruze/p/3819761.html
1.3 CGLib动态代理
鉴于Java动态代理的限制,我们有需要代理没有任何实现接口的类的时候,可以考虑使用CGLib。CGLib的全称是Code Generate Library。CGLib的使用使用十分广泛,我们这里要讲的Spring AOP,以及EasyMock等。
同样先上Demo代码,我们只需要实现MethodInterceptor接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* @author xiaobaoqiu Date: 16-3-10 Time: 下午7:15
*/
public class CglibDynamicProxy implements MethodInterceptor {
/**
* 动态生成代理类
*/
public Object generateProxy(Class cls) {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
// enhancer.setCallbackFilter(); //filter
enhancer.setSuperclass(cls);
return enhancer.create(); // Enhancer也包含带参数的create方法
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
doSomethingBefore();
Object result = proxy.invokeSuper(obj, args);
doSomethingAfter();
return result;
}
private void doSomethingBefore() {
System.out.println("CglibDynamicProxy: Before...");
}
private void doSomethingAfter() {
System.out.println("CglibDynamicProxy: After...");
}
}
//使用
public static void main(String[] args) {
CglibDynamicProxy proxy = new CglibDynamicProxy();
//注意: 原始类的instance不需要存在,只需要Class类型
//用接口IHello接, 或者 HelloImpl 接
IHello helloAProxy = (IHello)proxy.generateProxy(HelloImpl.class);
helloAProxy.hello();
System.out.println("-------------------------------------------------");
//用接口IHello接, 或者 HelloWithLogImpl 接
IHello helloBProxy = (IHello)proxy.generateProxy(HelloWithLogImpl.class);
helloBProxy.hello();
System.out.println("-------------------------------------------------");
//代理没有实现任何interface的类
HelloWithoutInterface helloCProxy = (HelloWithoutInterface)proxy.generateProxy(HelloWithoutInterface.class);
helloCProxy.hello();
}
同样我们debug一下,得到的信息如下,同样生成了代理类,类名称为proxy.sample.HelloImpl$$EnhancerByCGLIB$$b46b6f06,这个稀奇古怪的类名我们后面会分析:
下面还是尝试分析CGLib动态代理的原理。默认情况下生成的代理class文件只存储在内存中,我们可以在代码中设置一个环境变量:
1
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/home/xiaobaoqiu/cglib_proxy");
之后我们在目标目录下得到很多的class,其中的proxy目录包含了生成的class文件。我们发现一大堆的class文件,类名都是稀奇古怪:
1
2
3
4
5
xiaobaoqiu@xiaobaoqiu:~/cglib_proxy/proxy/javaProxy$ ll
-rw-rw-r-- 1 xiaobaoqiu xiaobaoqiu 2227 3月 21 18:38 HelloWithoutInterface$$EnhancerByCGLIB$$7d786e36.class
-rw-rw-r-- 1 xiaobaoqiu xiaobaoqiu 5555 3月 21 18:38 HelloWithoutInterface$$EnhancerByCGLIB$$e4e0e0f1.class
-rw-rw-r-- 1 xiaobaoqiu xiaobaoqiu 7744 3月 21 18:38 HelloWithoutInterface$$EnhancerByCGLIB$$e4e0e0f1$$FastClassByCGLIB$$814877d5.class
-rw-rw-r-- 1 xiaobaoqiu xiaobaoqiu 2673 3月 21 18:45 HelloWithoutInterface$$FastClassByCGLIB$$32a767a1.class
我们先看看class文件的生成策略。每个Class Generator(比如这里的Enhancer)都继承自AbstractClassGenerator(实现接口ClassGenerator,这个接口只有一个generateClass的方法),需要实现其generateClass()方法。generateClassName()方法用来生成Class名称:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private String generateClassName(Predicate nameTestPredicate) {
return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
}
//namingPolicy的默认实现NamingPolicy
public String getClassName(String prefix, String source, Object key, Predicate names) {
//prefix为被代理类的路径,
String base =
prefix + "$$" + //prefix为被代理类的路径
source.substring(source.lastIndexOf('.') + 1) + //获取生成代理类的类,比如我们这里的Enhancer
getTag() + "$$" + //getTag()默认为ByCGLIB
Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode()); //hashcode
String attempt = base;
int index = 2;
while (names.evaluate(attempt)) //如果有重复,则再在后面加上下标,小标从2开始
attempt = base + "_" + index++;
return attempt;
}
下面正式进入class文件的生成原理分析,还是从源代码入手,enhancer.create()最终进入AbstractClassGenerator.create()方法,我们发现最终return的Object是从内部变量obj得来,因此,我们看看ClassLoaderData的生成逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected Object create(Object key) {
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
data = new ClassLoaderData(classLoader);
newCache.put(classLoader, data);
CACHE = newCache;
}
}
}
this.key = key;
Object obj = data.get(this);
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
}
public ClassLoaderData(ClassLoader classLoader) {
this.classLoader = new WeakReference<ClassLoader>(classLoader);
Function<AbstractClassGenerator, Object> load =
new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this); //生成class的关键代码
return gen.wrapCachedClass(klass);
}
};
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}
因此我们将目光转到generate()中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Enhancer的generate()方法
protected Class generate(ClassLoaderData data) {
validate();
if (superclass != null) {
setNamePrefix(superclass.getName());
} else if (interfaces != null) {
setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
}
return super.generate(data); //父类AbstractClassGenerator
}
// AbstractClassGenerator的generate()方法
protected Class generate(ClassLoaderData data) {
//...
ClassLoader classLoader = data.getClassLoader();
this.setClassName(generateClassName(data.getUniqueNamePredicate())); //代理类的类名称的生成逻辑
//...
byte[] b = strategy.generate(this); //生成策略,默认实现DefaultGeneratorStrategy,生成class文件的字节码
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
...//异常处理
}
//DefaultGeneratorStrategy的generate()方法
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw); //这里调用最终的generateClass()逻辑,Visitor模式
return transform(cw.toByteArray()); //通过Visitor得到最后的字节码
}
所以最终的调用是Enhancer的generateClass()调用。这代码好晦涩,感觉和JVM加载字节码相关。
看一下CGLib生成的class文件,这个代理类继承了我们的被代理类并且实现了Factory类,类定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class HelloWithoutInterface$$EnhancerByCGLIB$$e4e0e0f1 extends proxy.javaProxy.HelloWithoutInterface implements net.sf.cglib.proxy.Factory {
private boolean CGLIB$BOUND;
public static java.lang.Object CGLIB$FACTORY_DATA;
private static final java.lang.ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final net.sf.cglib.proxy.Callback[] CGLIB$STATIC_CALLBACKS;
private net.sf.cglib.proxy.MethodInterceptor CGLIB$CALLBACK_0;
private static final java.lang.reflect.Method CGLIB$hello$0$Method;
private static final net.sf.cglib.proxy.MethodProxy CGLIB$hello$0$Proxy;
private static final java.lang.Object[] CGLIB$emptyArgs;
private static final java.lang.reflect.Method CGLIB$equals$1$Method;
private static final net.sf.cglib.proxy.MethodProxy CGLIB$equals$1$Proxy;
private static final java.lang.reflect.Method CGLIB$toString$2$Method;
private static final net.sf.cglib.proxy.MethodProxy CGLIB$toString$2$Proxy;
private static final java.lang.reflect.Method CGLIB$hashCode$3$Method;
private static final net.sf.cglib.proxy.MethodProxy CGLIB$hashCode$3$Proxy;
private static final java.lang.reflect.Method CGLIB$clone$4$Method;
private static final net.sf.cglib.proxy.MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() { /* compiled code */ }
final void CGLIB$hello$0() { /* compiled code */ } //代理的方法
public final void hello() { /* compiled code */ } //代理的方法
final boolean CGLIB$equals$1(java.lang.Object o) { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
final java.lang.String CGLIB$toString$2() { /* compiled code */ }
public final java.lang.String toString() { /* compiled code */ }
final int CGLIB$hashCode$3() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
final java.lang.Object CGLIB$clone$4() throws java.lang.CloneNotSupportedException { /* compiled code */ }
protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException { /* compiled code */ }
public static net.sf.cglib.proxy.MethodProxy CGLIB$findMethodProxy(net.sf.cglib.core.Signature signature) { /* compiled code */ }
public HelloWithoutInterface$$EnhancerByCGLIB$$e4e0e0f1() { /* compiled code */ }
public static void CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public static void CGLIB$SET_STATIC_CALLBACKS(net.sf.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
private static final void CGLIB$BIND_CALLBACKS(java.lang.Object o) { /* compiled code */ }
public java.lang.Object newInstance(net.sf.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public java.lang.Object newInstance(net.sf.cglib.proxy.Callback callback) { /* compiled code */ }
public java.lang.Object newInstance(java.lang.Class[] classes, java.lang.Object[] objects, net.sf.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
public net.sf.cglib.proxy.Callback getCallback(int i) { /* compiled code */ }
public void setCallback(int i, net.sf.cglib.proxy.Callback callback) { /* compiled code */ }
public net.sf.cglib.proxy.Callback[] getCallbacks() { /* compiled code */ }
public void setCallbacks(net.sf.cglib.proxy.Callback[] callbacks) { /* compiled code */ }
}
注意,我们生成的动态代理包含两个hello()相关的方法。我们可以使用javap获取其字节码,我们发现和我们被代理者同名的hello()方法是带代理逻辑的,而CGLIB$hello$0()这个则是原始被代理者的直接调用(不包含代理逻辑):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
xiaobaoqiu@xiaobaoqiu:~/cglib_proxy/proxy/javaProxy$ javap -c HelloWithoutInterface\$\$EnhancerByCGLIB\$\$e4e0e0f1.class
...
final void CGLIB$hello$0();
Code:
0: aload_0
1: invokespecial #36 // Method proxy/javaProxy/HelloWithoutInterface.hello:()V
4: return
public final void hello();
Code:
0: aload_0
1: getfield #38 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor;
4: dup
5: ifnonnull 17
8: pop
9: aload_0
10: invokestatic #42 // Method CGLIB$BIND_CALLBACKS:(Ljava/lang/Object;)V
13: aload_0
14: getfield #38 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor;
17: dup
18: ifnull 37
21: aload_0
22: getstatic #44 // Field CGLIB$hello$0$Method:Ljava/lang/reflect/Method;
25: getstatic #46 // Field CGLIB$emptyArgs:[Ljava/lang/Object;
28: getstatic #48 // Field CGLIB$hello$0$Proxy:Lnet/sf/cglib/proxy/MethodProxy;
31: invokeinterface #54, 5 // InterfaceMethod net/sf/cglib/proxy/MethodInterceptor.intercept:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;
36: return
37: aload_0
38: invokespecial #36 // Method proxy/javaProxy/HelloWithoutInterface.hello:()V
41: return
...
遗留问题:
(1).为什么一个类会生成多个代理类,各个代理类都是什么用处;
CGLib代理同样存在限制:
(1).private方法无法代理;
(2).final方法无法代理;
private方法和final方法看代理类的字节码会发现,代理类不会这些重写函数(子类没法重写),因此会自动调用父类的。
参考:
cglib源码分析(四):cglib 动态代理原理分析
CGLib: The Missing Manual
#1.4 Java动态代理 VS CGLib动态代理
简单总结对比一下两种动态代理:
代理
没有实现interface的类
protected方法
private方法
final类
final方法
构造函数private的类
Java动态代理
不支持
不支持
不支持
支持
支持
支持
CGLib动态代理
支持
支持
不支持
不支持
不支持
不支持
关于CGLib对protected方法的支持,可以在生成的代理类中看到.
1
2
3
4
CGLib报错信息:
final类: Cannot subclass final class proxy.javaProxy.HelloWithFinal
构造方法私有的类: No visible constructors in class proxy.javaProxy.HelloWithoutConstructor
final方法: 不报错,但没有代理逻辑
在性能方面,通常认为Java动态代理生成代理类比CGLib生成代理类快,但是CGLib的代理类运行期性能会优于Java动态代理的代理类。不过通常性能都不是问题,如果确实很关心性能,建议直接使用ASM。
参考:
Why do you think CGLib proxies are faster than JDK Proxies?
Implement Your Own Proxy-Based AOP Framework Blog
BeanDefinitionParserDelegate
AnnotationDrivenBeanDefinitionParser
参考:
Spring加载资源分析:http://www.blogjava.net/heavensay/archive/2013/10/28/405699.html
事务的坑
http://www.ibm.com/developerworks/library/j-ts1/
代理实现选择器:
AdviceMode
TransactionManagementConfigurationSelector
声明事务切面实现:
TransactionInterceptor
事务实现
Connection关闭自动提交
ConnectionHolder来保持Connection
参考:
http://openwares.net/java/spring_mybatis_transaction.html
http://my.oschina.net/guanzhenxing/blog/214228
http://www.mybatis.org/spring/zh/transactions.html
http://tracylihui.github.io/2015/07/28/spring/Spring%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86/
http://www.cnblogs.com/davenkin/archive/2013/02/16/java-tranaction-1.html
http://www.importnew.com/12300.html
详细介绍Spring事务管理: http://developer.51cto.com/art/200906/129854.htm
spring事务原理1-事务的抽象: http://sqtds.github.io/2014/06/09/2014/spring-tx1/
Spring官方文档Transaction Management: http://docs.spring.io/autorepo/docs/spring/3.2.x/spring-framework-reference/html/transaction.html
Spring官方文档Aspect Oriented Programming with Spring: http://docs.spring.io/spring/docs/3.0.x/reference/aop.html
StackOverFlow Spring - @Transactional - What happens in background?: http://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background
Transaction strategies: Understanding transaction pitfalls: http://www.ibm.com/developerworks/library/j-ts1/
Annotation-based Transactions in Spring: http://springinpractice.com/2008/03/18/annotation-based-transactions-in-spring
Design principle behind Transaction framework with Spring 3: http://stackoverflow.com/questions/11789857/design-principle-behind-transaction-framework-with-spring-3
Chapter 6. 使用Spring进行面向切面编程(AOP): http://shouce.jb51.net/spring/aop.html
wiki: http://wiki.corp.qunar.com/display/~yushen.ma/Spring+3.x-JDBC+Transaction
spring事务: http://wiki.corp.qunar.com/pages/viewpage.action?pageId=52084161
spring 事务: http://wiki.corp.qunar.com/pages/viewpage.action?pageId=93338632
aspectj事务: http://wiki.corp.qunar.com/pages/viewpage.action?pageId=92656954
Demo:
编程事务: http://www.tutorialspoint.com/spring/programmatic_management.htm
声明事务: http://www.tutorialspoint.com/spring/declarative_management.htm
@Transactional注解工作原理:http://blog.csdn.net/dslztx/article/details/46636079
分布式事务系列(1.2)Spring的事务体系: https://yq.aliyun.com/articles/39046
spring transaction源码分析–事务架构:http://www.cnblogs.com/davidwang456/p/4309038.html
http://blog.csdn.net/szwangdf/article/details/41516239
AopProxy
DefaultAopProxyFactory