设计模式之动态代理

        在我的前一篇博文静态代理中,使用静态代理模式时,我们需要在程序加载执行前,手动的创建好每个目标对象类的代理类。这样就导致我们如果有很多个需要被代理的类时,就必须手动的去创建好所有的每一个代理类,这样就会生成很多的代理文件,不易于代理的维护和管理。有没有什么办法可以不用生成这么多代理类呢?动态代理

        一 什么是动态代理

        代理类在程序运行时才被创建出来的方式称为动态代理。在这种方式中,我们不需要在程序执行前去生成对应的代理类,只需要在程序执行过程中,根据我们传递的目标对象去动态的创建即可。相比较静态代理,这种方式不需要我们去手动创建大批量的文件,更易于代理对象及方法的统一管理维护,比如我们需要对代理类做方法增强时就不需要去修改每一个代理类。

        二 动态代理实现

  创建两个接口

1 public interface ICatDao {
2 
3     /**
4      * 描述自己
5      */
6     void desc();
7 
8 }
1 public interface IDogDao {
2 
3     /**
4      * 描述自己
5      */
6     void desc();
7 
8 }

  创建接口的实现类

1 public class CatDaoImpl implements ICatDao {
2     @Override
3     public void desc() {
4         System.out.println("<<-----------喵喵----------->>");
5     }
6 }
1 public class DogDaoImpl implements IDogDao {
2     @Override
3     public void desc() {
4         System.out.println("<<-----------旺旺----------->>");
5     }
6 }

  创建动态代理类实现 InvocationHandler接口(JDK动态代理必须实现这个接口),我们使用提供的目标对象调用getProxy方法来生成代理类,执行目标对象提供的方法时会通过反射执行invoke方法执行

 1 public class DynamicProxy implements InvocationHandler {
 2 
 3     /**
 4      * 目标对象
 5      */
 6     private Object target;
 7 
 8     public DynamicProxy() {
 9     }
10 
11     public Object getProxy(Object intf){
12         this.target = intf;
13         //args1:类加载器
14         //args2:目标对象接口方法
15         //InvocationHandler接口。所有动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理
16         return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
17     }
18 
19     @Override
20     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21         method.invoke(target, args);
22         return null;
23     }
24 
25 }

  测试,创建main方法生成代理类,执行方法

 1 public static void main(String[] args) {
 2 
 3         ICatDao catDao = new CatDaoImpl();
 4         ICatDao catDaoProxy = (ICatDao) new DynamicProxy().getProxy(catDao);
 5         catDaoProxy.desc();
 6 
 7         IDogDao dagDao = new DogDaoImpl();
 8         IDogDao dagDaoProxy = (IDogDao) new DynamicProxy().getProxy(dagDao);
 9         dagDaoProxy.desc();
10 
11     }

  执行结果如下,可以看到动态的生成了每一个目标对象,且可以正常执行

  如果我们需要对做方法增强,我们只需要修改invoke就可以了,如

1 @Override
2     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
3         System.out.println("方法【"+method.getName()+"】要开始执行了");
4         method.invoke(target, args);
5         System.out.println("方法【"+method.getName()+"】已经执行结束");
6         return null;
7     }

  执行测试方法,结果如下,可以看到对所有的代理类的方法都做了增强

   三 源码分析

  代理对象类生成是调用Proxy类的newProxyInstance方法实现的,我们看看具体的方法

 1 /**
 2      *
 3      * @param loader 定义代理类的类加载器
 4      * @param interfaces 要实现的代理类的接口列表,不能超过 65535
 5      * @param h
 6      * @return
 7      * @throws IllegalArgumentException
 8      */
 9     @CallerSensitive
10     public static Object newProxyInstance(ClassLoader loader,
11                                           Class<?>[] interfaces,
12                                           InvocationHandler h)
13             throws IllegalArgumentException
14     {
15         // InvocationHandler 不能为空
16         Objects.requireNonNull(h);
17 
18         final Class<?>[] intfs = interfaces.clone();
19         final SecurityManager sm = System.getSecurityManager();
20         if (sm != null) {
21             //校验接口是否可以被访问
22             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
23         }
24 
25         //生成代理类
26         Class<?> cl = getProxyClass0(loader, intfs);
27 
28         //用指定的InvocationHandler调用其构造函数
29         try {
30             if (sm != null) {
31                 //对代理类进行权限校验
32                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
33             }
34 
35             //根据参数生成构造器
36             final Constructor<?> cons = cl.getConstructor(constructorParams);
37 
38             final InvocationHandler ih = h;
39 
40             if (!Modifier.isPublic(cl.getModifiers())) {
41                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
42                     public Void run() {
43                         cons.setAccessible(true);
44                         return null;
45                     }
46                 });
47             }
48 
49             //使用构造器生成实例
50             return cons.newInstance(new Object[]{h});
51 
52         } catch (IllegalAccessException|InstantiationException e) {
53             throw new InternalError(e.toString(), e);
54         } catch (InvocationTargetException e) {
55             Throwable t = e.getCause();
56             if (t instanceof RuntimeException) {
57                 throw (RuntimeException) t;
58             } else {
59                 throw new InternalError(t.toString(), t);
60             }
61         } catch (NoSuchMethodException e) {
62             throw new InternalError(e.toString(), e);
63         }
64     }
1 private static Class<?> getProxyClass0(ClassLoader loader,
2                                            Class<?>... interfaces) {
3         if (interfaces.length > 65535) {
4             throw new IllegalArgumentException("interface limit exceeded");
5         }
6 
7         //如果实现给定接口的给定加载器定义的代理类存在,那么它将返回缓存的副本; 否则,它将通过ProxyClassFactory创建代理类
8         return proxyClassCache.get(loader, interfaces);
9     }
由于个人能力有限,难免有错误之处,敬请读者指正,不胜感激。
原文地址:https://www.cnblogs.com/love-wzy/p/10175151.html