动态代理两种实现方式
今天又是周末,自己的春招也差不多结束了,百般无聊的状态下想写点东西。
我想先提一个东西,比如你想要计算一段代码的执行时间,那么你之前肯定是这样写的。
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大概就是用这两种方法实现的。