动态代理两种实现方式

今天又是周末,自己的春招也差不多结束了,百般无聊的状态下想写点东西。

我想先提一个东西,比如你想要计算一段代码的执行时间,那么你之前肯定是这样写的。

1 /**
2  * 先定义一个接口
3  * 
4  * @author chang
5  */
6 public interface DoSomthing {
7 
8     void doSomthing() throws InterruptedException;
9 }
 1 /**
 2  * 实现类
 3  * @author chang
 4  */
 5 public class DoSomthingImpl implements DoSomthing {
 6     
 7     @Override
 8     public void doSomthing() throws InterruptedException {
 9         Thread.sleep(100);
10         System.out.println("这是主体的同容  " + System.currentTimeMillis());
11         Thread.sleep(100);
12     }
13 }

 

写死的方法,也是最笨的方法。

在doSomthing前后加上before(), after()。这两个方法。 如果有其他方法想要执行befor,after,同样写死在代码里面。

 

这就是所谓的静态代理,非常的麻烦以及代码十分的重复冗余,所以出现了伟大的动态代理。

 

JDK动态代理:

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 
 5 public class JDKDynamicProxy implements InvocationHandler{
 6 
 7     Object o = null;
 8     
 9     public JDKDynamicProxy(Object o) {
10         this.o = o;
11     }
12     
13     public Object getProxy() {
14         
15         return Proxy.newProxyInstance(o.getClass().getClassLoader(), 
16                 o.getClass().getInterfaces(), this);
17     }
18     
19     @Override
20     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21         
22         before();
23         Object res = method.invoke(o, args);
24         after();
25         return res;
26     }
27     
28     void before() {
29         System.out.println(System.currentTimeMillis());
30     }
31     
32     void after() {
33         System.out.println(System.currentTimeMillis());
34     }
35     
36 }
1 public class Test {
2     public static void main(String[] args) throws InterruptedException {
3         
4         JDKDynamicProxy jp = new JDKDynamicProxy(new DoSomthingImpl());
5         DoSomthing ds = (DoSomthing) jp.getProxy();
6         ds.doSomthing();
7     }
8 }

会不会发觉扩展十分的方便。每次只用new一个动态代理类,并且把实现类的对象传过去,jdk就会自动的代理这个方法。

每次你调用doSomthing方法的时候,自动执行before和after方法,非常的方便。

但有个问题,JDK 给我们提供的动态代理只能代理接口,而不能代理没有接口的类。因为你的Proxy.newProxyInstance要传一个接口的参数过去,那又要怎么办呢?

 

CGLib动态代理

 1 import java.lang.reflect.Method;
 2 import net.sf.cglib.proxy.Enhancer;
 3 import net.sf.cglib.proxy.MethodInterceptor;
 4 import net.sf.cglib.proxy.MethodProxy;
 5 
 6 public class CGLibDynamicProxy implements MethodInterceptor{
 7 
 8     public CGLibDynamicProxy() {}
 9     
10     public <T> Object getProxy(Class<T> cls) {
11         return Enhancer.create(cls, this);
12     }
13     
14     @Override
15     public Object intercept(Object target, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
16         
17         before();
18         Object res = proxy.invokeSuper(target, arg2);
19         after();
20         return res;
21     }
22     
23     void before() {
24         System.out.println(System.currentTimeMillis());
25     }
26     
27     void after() {
28         System.out.println(System.currentTimeMillis());
29     }
30 }
1 public class Test {
2     public static void main(String[] args) throws InterruptedException {
3         
4         CGLibDynamicProxy cg = new CGLibDynamicProxy();
5         DoSomthing ds = (DoSomthing) cg.getProxy(DoSomthingImpl.class);
6         ds.doSomthing();
7     }
8 }

 

同样new一个CGLibDynamicProxy对象,然后通过getProxy方法获得对象,然后直接调用方法即可。

而Spring框架底层的AOP大概就是用这两种方法实现的。

posted on 2018-04-21 10:55 wenbochang 阅读(...) 评论(...) 编辑 收藏

导航

公告