动态代理之JDK代理与CGlib代理

       我们都知道代理分为静态代理和动态代理,然而静态代理比较简单,直接将需要被代理的类作为代理类的一

个成员变量即可,但是这种代理在复杂的条件下会变得异常繁琐,且容易出错。这里我们主要说动态代理。

      一.   javaJDK的动态代理:

             这种代理只要给出接口对象和子类的实现,那么就可以实现,其中主要借助于Proxy类的静态方newProxyInstance和InvocationHandler的invoke的方法重写,案例如下:

package com.company;

/**
 * Created by Dqd on 2017/4/8.
 */
public interface Animal {
    public void shout();
}



public class Dog implements Animal {
    @Override
    public void shout() {
        System.out.println("汪汪..");
    }
}




public class JDKProxy implements InvocationHandler {
    //被代理对象
    private Object animal;
    //之所以为动态代理,就是可以接收到不同类型的参数
    public Object getInstance(Object animal){
        this.animal = animal;
        return Proxy.newProxyInstance(animal.getClass().getClassLoader()
                ,animal.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before shout");
        method.invoke(animal,args);
        System.out.println("After shout");
        return null;
    }
}


Test:

public class  Main {
    public static void main(String[] args){
        Animal animal = (Animal) new JDKProxy().getInstance(new Dog());
        animal.shout();
    }
}


输出结果为:

Before shout
汪汪..
After shout


       虽然我们实现了动态代理,但是还是不明白为什么使用Proxy.newProxyInstance()就可以生成代理对象的

下面是Proxy类的newProxyInstance的源码:

/** 
 * loader:类加载器 
 * constructorParams是InvocationHandler实现类中的变量
 * interfaces:目标对象实现的接口 
 * h:InvocationHandler的实现类 
 */  
public static Object newProxyInstance(ClassLoader loader,  
                      Class[] interfaces,  
                      InvocationHandler h)  
    throws IllegalArgumentException  
    {  
    if (h == null) {  
        throw new NullPointerException();  
    }  
  
    /* 
     * Look up or generate the designated proxy class. 
     */  
    Class cl = getProxyClass(loader, interfaces);  
  
    /* 
     * Invoke its constructor with the designated invocation handler. 
     */  
    try {  
            // 调用代理对象的构造方法(也就是$Proxy0(InvocationHandler h))  
        Constructor cons = cl.getConstructor(constructorParams);  
            // 生成代理类的实例并把MyInvocationHandler的实例传给它的构造方法  
        return (Object) cons.newInstance(new Object[] { h });  
    } catch (NoSuchMethodException e) {  
        throw new InternalError(e.toString());  
    } catch (IllegalAccessException e) {  
        throw new InternalError(e.toString());  
    } catch (InstantiationException e) {  
        throw new InternalError(e.toString());  
    } catch (InvocationTargetException e) {  
        throw new InternalError(e.toString());  
    }  
    }  

PS:通过传入的参数(接口)克隆接口得到interfaces,然后再结合类加载器,得到一个继承Proxy的Class对象(ps:这里的Class对象生成的过程涉及到了缓存的问题,就是这里的getProxyClass方法),通过这个对象得到构造方法对象,构造方法对象再生成实例,这就是代理对象的生成过程。


代理对象的生成明确了,那么实现InvokeHandler的invoke方法由谁来调用呢?


根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类;实例化$Proxy0并在构造方法中把继承了InvocationHandler的实例当做参数传过去,接着

$Proxy0调用父类Proxy的构造器,为成员变量赋值;$Proxy0实例强制转换成Animal,并将引用赋给animal。当执行animal.request()方法时,就调用了

$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke().

      总结:生成代理类的时候,首先调用Proxy.newInstance()方法,并将接口的类加载器,所拥有的接口和InvocationHandler对象传递过去,生成一个继承Proxy的Class对象,然后通过父类的构造器将构造出一个Animal

对象,然后调用request()方法,此方法再去调用invoke()方法。



二.CGlib的动态代理:

package com.company;

/**
 * Created by Dqd on 2017/4/8.
 */
public class Animal {
    public void Shout(){
        System.out.println("汪汪...");
    }
}



//在JDK自带的动态代理中实现的是InvocationHandler

public class CGlibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用之前");
        methodProxy.invokeSuper(o,objects);
        System.out.println("调用之后");
        return null;
    }
    public Object getCGlibProxy(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码动态的创建子类
        return enhancer.create();
    }
}


public class  Main {
    public static void main(String[] args){
        CGlibProxy cGlibProxy = new CGlibProxy();
        Animal animal = (Animal) cGlibProxy.getCGlibProxy(Animal.class);
        animal.Shout();
    }
}






你可能感兴趣的:(JAVA)