spring中的设计模式——动态代理(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cd18333612683/article/details/80794528
前言

今天一定要把这一篇博客补上,前段时间看了看动态代理的jdk方式如何实现,用起来简单,但是jdk中的实现就不那么容易了~~

代理模式的特点
  1. 有执行者、被代理者两种角色
  2. 这件事一定要做,自己不想做,或者没有时间做
  3. 执行者需要获取被代理人的资料
    例子:取快递、中介、媒人等
代理模式的应用小例子——Celine取快递

celine的快递到了,但是她去公司上班了,所以她爸帮她取得快递。从这个例子中,我们抽象出了被代理人(celine),代理人(她爸爸),接口(取快递)

(1) 接口

public interface Receive {
    public void Receive();
}

(2)celine

/**
 * 被代理类
 */
public class Celine implements Receive {

    @Override
    public void Receive() {
        System.out.println("Celine在上班,没有办法取快递");
    }

}

(3)代理类

/**
 * 代理类需要实现InvocationHandler接口,并且重写invoke方法,其中的method.invoke(target, args)就是celine具体实现接口的方法
 */
public class CelineFather implements InvocationHandler {
    private Object target;

    public CelineFather(Object target) {
        super();
        this.target=target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        method.invoke(target, args);
        System.out.println("celine她爸取得快递");
        return null;
    }

}

(4)测试类

public class TestJdkDynamicProxy {
    public static void main(String[] args){
        Celine celine=new Celine();
        Class celineClass=celine.getClass();
        //通过newProxyInstance生成代理对象
        Receive Receiver = (Receive)Proxy.newProxyInstance(celineClass.getClassLoader(), celineClass.getInterfaces(),
                 new CelineFather(celine));
        //实际调用的是代理类中的invoke方法
        Receiver.Receive();
    }
}
JDK实现原理
  1. 拿到被代理对象的引用,然后获取他的接口
  2. jdk代理重新生成一个类,同时实现代理对象所实现的接口(所以jdk的动态代理必须有接口)
  3. 拿到对象的引用
  4. 重新动态生成一个class字节码
  5. 重新编译
jdk源码中几个重要的方法

首先提出几个疑问:
1.为什么最后真正实现的是代理类的invoke方法?
2.为什么newProxyInstance返回值要强转成接口的实例?
3.newProxyInstance没有转成接口类之前是什么?

我们从newProxyInstance这个方法入手,首先这个方法传入了三个参数,分别是Celine的类加载器,Celine实现的接口数组,CelineFather的对象

这个方法为我们做了三件比较重要的事情:
1、生成代理类
2、获得代理类的构造函数
3、根据构造函数实例化代理类(生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法 )

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 生成代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        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;
                    }
                });
            }
            //生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法 
            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);
        }
    }

getProxyClass0(loader, intfs)这个方法是最为重要的,他会生成一个$Proxy0的类,经过反编译,我们看看这个类是什么样子的(下边代码来源于网络,我没有下载反编译工具,所以就在网上找了一个)

这个类他会实现我们的被代理类中所有的方法,最为重要的是其中的super.h.invoke(this, m3, null); 方法,这也就是为什么调用invoke方法实现的确实代理类的invoke方法,而且invoke方法会调用Celine的receive方法,第二个参数m3就是被代理类对象的receive的方法,这也解决了我们的三个疑问

import dynamic.proxy.UserService;  
import java.lang.reflect.*;  

public final class $Proxy11 extends Proxy  
    implements UserService  
{  

    // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例  
    public $Proxy11(InvocationHandler invocationhandler)  
    {  
        super(invocationhandler);  
    }  

    public final boolean equals(Object obj)  
    {  
        try  
        {  
            return ((Boolean)super.h.invoke(this, m1, new Object[] {  
                obj  
            })).booleanValue();  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

    /** 
     * 这个方法是关键部分 
     */  
    public final void add()  
    {  
        try  
        {  
            // 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了  
            super.h.invoke(this, m3, null);  
            return;  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

    public final int hashCode()  
    {  
        try  
        {  
            return ((Integer)super.h.invoke(this, m0, null)).intValue();  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

    public final String toString()  
    {  
        try  
        {  
            return (String)super.h.invoke(this, m2, null);  
        }  
        catch(Error _ex) { }  
        catch(Throwable throwable)  
        {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

    private static Method m1;  
    private static Method m3;  
    private static Method m0;  
    private static Method m2;  

    // 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法  
    static   
    {  
        try  
        {  
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
                Class.forName("java.lang.Object")  
            });  
            m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
        }  
        catch(NoSuchMethodException nosuchmethodexception)  
        {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        }  
        catch(ClassNotFoundException classnotfoundexception)  
        {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }  
}  

猜你喜欢

转载自blog.csdn.net/cd18333612683/article/details/80794528