Java-JDK与CGLIB动态代理的实现

动态代理技术可用于运行期动态织入目标方法

JDK动态代理

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
public interface SayService {
void say(String name);
}
public class SayServiceImpl implements SayService {
@Override
public void say(String name) {
System.out.println(name);
}
}
public class DynamicProxy implements InvocationHandler {

private Object target;

public DynamicProxy(Object target) {
this.target = target;
}

//生成代理对象
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("代理前");
//这里用的target而非方法参数的proxy
Object obj = method.invoke(target, args);
System.out.println("代理后");
return obj;
}
}

编写测试方法

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
public class JDKProxyTest {

public static void main(String[] args) {

SayService sayService = new SayServiceImpl();

SayService proxy = new DynamicProxy(sayService).getProxy();

proxy.say("changjie");

//将jdk中生成代理类输出到本地.Class文件,之后可以通过反编译软件打开查看
createProxyClassFile("SayService",sayService.getClass().getInterfaces());
}


private static void createProxyClassFile(String name, Class<?> [] interfaces){
//该方法为jdk中生成代理类的核心方法
byte[] data = ProxyGenerator.generateProxyClass(name,interfaces);
FileOutputStream out =null;
try {
out = new FileOutputStream(name+".class");
System.out.println((new File(name)).getAbsolutePath());
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null!=out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

输出

1
2
3
4
代理前
changjie
代理后
/Users/admin/IdeaProjects/spring-note/SayService

反编译其生成的动态代理类

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 final class SayService extends Proxy implements me.changjie.aop.proxy.SayService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;

public SayService(InvocationHandler var1) throws {
super(var1);
}

public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}

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);
}
}

public final void say(String var1) throws {
try {
//调用父类Proxy持有的InvocationHandle对象的invoke方法
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}

public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (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", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("me.changjie.aop.proxy.SayService").getMethod("say", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}

可知JDK通过多态和反射生成的动态代理类,生成的代理类继承了Proxy类(持有InvocationHandler对象),实现了与被代理类相同的接口,这里也能反映出为什么JDK只能代理实现了接口的类,因为生成的代理类需要继承Proxy,由于单继承限制,只能和被代理类实现相同的接口来达到兄弟关系

CGLIB动态代理

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
public class CglibProxyTest {

public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
////设置增强类的父类
enhancer.setSuperclass(SayServiceImpl.class);
//设置拦截器,拦截对父类所有非final方法的调用
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getName());
System.out.println("cglib动态代理before");
//调用父类方法
Object object = methodProxy.invokeSuper(o, objects);
System.out.println("cglib动态代理after");
return object;
}
});

//创建动态代理对象
SayService sayService = (SayService) enhancer.create();
System.out.println(sayService.getClass().getName());

sayService.say("changjie");
}
}

CGLIB是生成目标类的子类,来织入目标类方法,所以对于final修饰的方法无法代理

总结

JDK生成的动态代理类与被代理类是兄弟关系,二者实现了相同接口,所以只能对实现了接口的类进行代理
CGLIB生成的代理类与被代理类是父子关系,所以无法对final修饰的方法进行代理

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×