1 package proxy.dynamicproxy;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6
7
8 /**
9 * 需要实现InvocationHandler接口,内部维护一个实际类实例
10 *
11 */
12 public class JdkProxyHandler implements InvocationHandler {
13
14 private Object realObject;
15
16 public Object proxy(Object realObject){
17 this.realObject = realObject;
18 return Proxy.newProxyInstance(this.realObject.getClass().getClassLoader(),
19 this.realObject.getClass().getInterfaces(), this);
20 }
21
22 /**
23 *
24 * @param proxy 动态生成的代理类实例
25 * @param method 方法实例
26 * @param args 方法参数
27 * @return
28 * @throws Throwable
29 */
30 @Override
31 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
32 System.out.println("我是代理人:大明星唱歌开始前,我先宣传一下:巴拉巴拉。。。");
33
34 // 调用实际类的方法,并传入参数,内部是反射机制
35 Object ret = method.invoke(this.realObject, args);
36
37 System.out.println("我是代理人:大明星唱歌完毕了,我来总结一下:巴拉巴拉。。。");
38
39 return ret;
40 }
41 }
1 package proxy.dynamicproxy;
2
3 import net.sf.cglib.proxy.Enhancer;
4 import net.sf.cglib.proxy.MethodInterceptor;
5 import net.sf.cglib.proxy.MethodProxy;
6
7 import java.lang.reflect.Method;
8
9 /**
10 * 需要实现MethodInterceptor接口
11 * cglib相关依赖:
12 * ant-1.6.2.jar
13 * asm-3.1.jar
14 * asm-util-3.1.jar
15 * cglib-2.2.2.jar
16 */
17 public class CglibProxyHandler implements MethodInterceptor {
18
19 public Object proxy(Object realObject){
20
21 // 使用字节码增强器 四个固定步骤:
22 // 1、new字节码增强器
23 // 2、设置当前类实例为回调
24 // 3、将实际类实例设置为父类
25 // 4、创建一个代理类
26 Enhancer enhancer = new Enhancer();
27 enhancer.setCallback(this);
28 enhancer.setSuperclass(realObject.getClass());
29 // 这里会生成代理类、代理类的FastClass辅助类、实际类的FastClass辅助类
30 // 辅助类为代理类和实际类的每个方法生成一个唯一的id
31 // 用于在调用intercept方法时,通过唯一id就可以调用对应的方法
32 // 不再走反射机制,提高性能
33 return enhancer.create();
34 }
35
36 /**
37 *
38 * @param o 代理类的实例
39 * @param method 方法实例
40 * @param objects 方法参数
41 * @param methodProxy 方法代理
42 * @return
43 * @throws Throwable
44 */
45 @Override
46 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
47
48 System.out.println("我是代理人:大明星唱歌开始前,我先宣传一下:巴拉巴拉。。。");
49
50 // 这里如果使用 method.invoke方法,就等同于走了反射机制去调用方法,性能不高
51 // 而且还需要另外维护实际类实例
52 // Object ret = method.invoke(this.realObject, objects);
53
54 Object ret = methodProxy.invokeSuper(o, objects);
55
56 System.out.println("我是代理人:大明星唱歌完毕了,我来总结一下:巴拉巴拉。。。");
57
58 return ret;
59 }
60 }
1 package proxy.dynamicproxy;
2
3 import net.sf.cglib.core.DebuggingClassWriter;
4 import proxy.staticproxy.IStar;
5 import proxy.staticproxy.RealStar;
6
7 public class Test {
8 public static void main(String[] args) {
9
10 /**
11 * 还是以“代理人”和“大明星”为例
12 * jdk动态代理:适用于大明星实现某接口的情况,且只能用于实现接口的情况
13 * 不能用于未实现任何接口的类,因为生成的动态代理类要继承自Proxy、同时实现大明星接口。
14 * cglib动态代理:适用于任何类。它是采用动态代理类直接继承大明星类的方式,将大明星当作父类
15 * 覆写大明星类的所有方法(除final修饰的方法,wait方法,notify方法)
16 *
17 * 优缺点:
18 * jdk方式,只能针对接口,底层直接写字节码的方式生成代理类,所以生成代理类速度快
19 * 但是代理类执行方法时,通过反射的方式去执行,速度不如cglib方式
20 * cglib方式,可以适用于任何类,底层使用ASM框架生成字节码,因为采用FastClass机制
21 * 在生成代理类的同时还要生成代理类和大明星类的对应FastClass类(辅助类)
22 * 这两个辅助类的作用是:对应FastClass辅助类会为代理类和大明星类的每一个方法
23 * (除final修饰的方法,wait方法,notify方法)生成唯一id,这样在后面的调用方法时
24 * 不再通过反射去执行逻辑,而是直接根据id找到对应的方法去执行,提高性能,但相对的,生成字节码速度较慢
25 */
26 boolean isUseJdkProxy = false;
27
28 if (isUseJdkProxy) {
29 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
30
31 IStar star = (IStar) new JdkProxyHandler().proxy(new RealStar());
32 star.sing();
33 }
34 else {
35
36 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
37 "C:\Users\Administrator\IdeaProjects\untitled\cglibClass");
38
39 IStar star = (IStar) new CglibProxyHandler().proxy(new RealStar());
40
41 // 这一步里面的具体流程:
42 // 动态代理类的sing方法 --> CglibProxyHandler的intercept方法
43 // --> 实际类执行前的行为代理 --> MethodProxy.invokeSuper方法
44 // --> 根据唯一id在FastClass里找到对应的实际方法
45 // --> 代理类的FastClass内部:让代理类调用实际方法
46 // --> 代理类的实际方法内部一般就是直接调用父类(被代理类)的方法
47 // --> 返回父类方法的返回值
48 star.sing();
49
50 }
51 }
52 }