Java中动态代理的实现(实现机制)

代理:设计模式

代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

   为了方便说明,这里写一个简单的例子来实现动态代理。 

       

Java代码   收藏代码
  1. //抽象角色(动态代理只能代理接口)  
  2. public interface Subject {  
  3.       
  4.     public void request();  
  5. }  

Java代码   收藏代码
  1. //真实角色:实现了Subject的request()方法  
  2. public class RealSubject implements Subject{  
  3.       
  4.     public void request(){  
  5.         System.out.println("From real subject.");  
  6.     }  
  7. }  

Java代码   收藏代码
  1. //实现了InvocationHandler  
  2. public class DynamicSubject implements InvocationHandler  
  3. {  
  4.     private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  
  5.   
  6.     public DynamicSubject()  
  7.     {  
  8.     }  
  9.   
  10.     public DynamicSubject(Object obj)  
  11.     {  
  12.         this.obj = obj;  
  13.     }  
  14.   
  15.     //这个方法不是我们显示的去调用  
  16.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  17.     {  
  18.         System.out.println("before calling " + method);  
  19.   
  20.         method.invoke(obj, args);  
  21.   
  22.         System.out.println("after calling " + method);  
  23.   
  24.         return null;  
  25.     }  
  26.   
  27. }  

Java代码   收藏代码
  1. //客户端:生成代理实例,并调用了request()方法  
  2. public class Client {  
  3.   
  4.     public static void main(String[] args) throws Throwable{  
  5.         // TODO Auto-generated method stub  
  6.   
  7.         Subject rs=new RealSubject();//这里指定被代理类  
  8.         InvocationHandler ds=new DynamicSubject(rs);  
  9.         Class<?> cls=rs.getClass();  
  10.           
  11.         //以下是一次性生成代理  
  12.           
  13.         Subject subject=(Subject) Proxy.newProxyInstance(  
  14.                 cls.getClassLoader(),cls.getInterfaces(), ds);  
  15.     }
  16. }      
  17.       
以上是借鉴以为博主的文章:

以下是进行分析的过程:

java动态代理的类和接口(jdk1.6源码)

1,java.lang.reflect.Proxy:动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。

主要的方法有四个:

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
public static InvocationHandler getInvocationHandler(Object proxy) 

// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
public static Class<?> getProxyClass(ClassLoader loader, 
Class<?>... interfaces)

// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
public static boolean isProxyClass(Class<?> cl) 

// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
public static Object newProxyInstance(ClassLoader loader,
 Class<?>[] interfaces,InvocationHandler h)
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13


源码如下(写的简单,可以自行)

Java代码  

  1. package java.lang.reflect;
    import ...

    public class Proxy implements java.io.Serializable {

        private static final Class<?>[] constructorParams ={ InvocationHandler.class };

        // 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
        @CallerSensitive
        public static InvocationHandler getInvocationHandler(Object proxy)
            throws IllegalArgumentException
        {
            if (!isProxyClass(proxy.getClass())) {
                throw new IllegalArgumentException("not a proxy instance");
            }

            final Proxy p = (Proxy) proxy;
            final InvocationHandler ih = p.h;
            if (System.getSecurityManager() != null) {
                Class<?> ihClass = ih.getClass();
                Class<?> caller = Reflection.getCallerClass();
                if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
                                                        ihClass.getClassLoader()))
                {
                    ReflectUtil.checkPackageAccess(ihClass);
                }
            }
            return ih;
        }

  2.     // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
        public static boolean isProxyClass(Class<?> cl) {
            return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
        }

  3.     // 方法 3:该方法用于判断指定类对象是否是一个动态代理类
        @CallerSensitive
        public static Class<?> getProxyClass(ClassLoader loader,
                                             Class<?>... interfaces)
            throws IllegalArgumentException
        {
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }

            return getProxyClass0(loader, intfs);
        }

        // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
        CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)  
        {
            Objects.requireNonNull(h);
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }     
            Class<?> cl = getProxyClass0(loader, intfs);
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }


                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }

    }


2,java.lang.reflect.InvocationHandler:调用处理器接口,自定义invokle方法,用于实现对于真正委托类的代理访问。

/**
 该方法负责集中处理动态代理类上的所有方法调用。
 第一个参数既是代理类实例,
 第二个参数是被调用的方法对象
 第三个方法是调用参数。
 调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
*/
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable;
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3,java.lang.ClassLoader:类装载器类,将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy类与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 
每次生成动态代理类对象时都需要指定一个类装载器对象:newProxyInstance()方法第一个参数

动态代理机制

java动态代理创建对象的过程为如下步骤: 
1,通过实现 InvocationHandler 接口创建自己的调用处理器;

// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..); //此处的InvocationHandlerImpl 相当于上面demo的 DynamicSubject implements InvocationHandler  
 
 
  • 1
  • 2
  • 3

2,通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
 
 
  • 1
  • 2

3,通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
 
 
  • 1
  • 2

4,通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
 
 
  • 1
  • 2

为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建






       


       
           

Java代码   收藏代码
  1. //真实角色:实现了Subject的request()方法  
  2. public class RealSubject implements Subject{  
  3.       
  4.     public void request(){  
  5.         System.out.println("From real subject.");  
  6.     }  
  7. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值