简介
我所理解的动态代理,最后的运行方式其实是一个静态代理加上一些反射机制,请注意,我说的是最后的运行方式
静态代理
抛开动态代理先不说,先看一下什么是静态代理,明白了静态代理,那么动态代理最后是如何运行的读完本篇文章基本上也就明白了
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
| public interface Service { public void doSomething(String context); }
public class ServiceImpl implements Service { @Override public void doSomething(String context) { System.out.println("do " + context); } }
public class StaticProxy {
private Service service;
public StaticProxy(Service service) { this.service = service; }
public void doSomething(String content) { System.out.println("do pre"); service.doSomething(content); System.out.println("do post"); } }
public class StaticMain { public static void main(String[] args) { StaticProxy proxy = new StaticProxy(new ServiceImpl()); proxy.doSomething("coding"); } }
|
这就是一个简单的静态代理的例子,把ServiceImpl的执行交给了StaticProxy来执行,在执行的前后可以添加do pre和do post的业务逻辑。
StaticProxy会在编译期就被编译成一个class文件被加载(这与动态代理有很大的区别)
动态代理
再来看动态代理,先不说动态代理的实现过程,上面说到是否编译成class文件是静态代理与动态代理的一个很大的区别。那这就表明,动态代理是没有class文件的,那它是怎么实现的呢?其实,我个人理解动态代理之所以叫做动态的,就是这个生成的过程是不定的。在运行时生成一份代理类的字节码并加载到jvm中。
先来看一下最后生成的字节码类,就以上面的类型为例
1 2 3 4 5 6 7 8 9 10 11 12
| public final class $Proxy1 extends Proxy implements Service { private InvocationHandler h; private $Proxy1() {} private $Proxy1(InvocationHandler h) { this.h = h; } public void doSomething(String content) { Method method = Service.class.getMethod("doSomething", new Class[]{String.class}); return h.invoke(this, method, new Object[]{new String(content)}); } }
|
看一下$Proxy1这个类与上面的StaticProxy的结构是不是类似,
- 都实现了Service
- 都是将接口的实现注入到构造函数中,为接口提供具体的实现类
- 最后都调用doSomething来调用具体的业务,只不过在动态代理里面通过反射来调用
看完$Proxy1,个人感觉就是一个静态代理的一个变种,把这个结果看明白了,那后面其实都是一些模板代码,目的就是为了生成这个类
有人会问$Proxy1,为什么会叫这个名字,我只能说我不知道,jvm就是这么做的,以\$开头,以数字标号来结尾。我现在不关心,我很开心我揭开动态代理的一层神秘的面纱,至少,不再像以前那样让人感觉高不可攀了(其实,还有很多层没揭开)
那下面就来看一下那些模板代码把
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
| public interface Service { public void doSomething(String context); }
public class ServiceImpl implements Service { @Override public void doSomething(String context) { System.out.println("do " + context); } }
public class ServiceInvocationHandler implements InvocationHandler {
private Object object;
public ServiceInvocationHandler(Object object) { this.object = object; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do pre"); method.invoke(object, args); System.out.println("do post"); return null; } }
public class DynamicMain {
public static void main(String[] args) {
Service service = new ServiceImpl(); ServiceInvocationHandler handler = new ServiceInvocationHandler(service);
Service proxyService = (Service) Proxy.newProxyInstance(handler.getClass().getClassLoader(), service.getClass().getInterfaces(), handler); proxyService.doSomething("coding"); } }
|
Service与ServiceImpl与静态代理没什么区别,将静态代理的代理类换成了InvocationHandler处理器的实现类。再有就是调用方式变了一下。
这里从main函数开始看,先指定Service的实现类,并构造Handler实现类。下面是重点,就是下面这行代码,用来生成$Proxy1这个字节码类的
Proxy的newProxyInstance方法,首先传递一个classloader,用这个classloader来加载生成的字节码类到jvm中;第二个参数是ServiceImpl实现的接口(即Service),使生成的字节码类也实现这个接口;第三个参数就是这个自定义的Handler了,将自定义的ServiceInvocationHandler传递给了$Proxy1中的InvocationHandler接口。
proxyService.doSomething,其实就是调用的$Proxy1的doSomething方法,然后再调用invoke方法。
怎么样,现在是不是已经对动态代理的理解又加深了一步呢!!!🙂