Java动态代理

    Java提供的动态代理,是“代理模式”的一个实现。代理模式简介:http://www.cnblogs.com/endlu/p/5169749.html

    静态代理有一定的弊端,为每一个被代理类都编写一个代理类会让系统变得臃肿,而且不够灵活。动态代理,是在运行时动态的生成一个代理类和代理对象。解决这方面的问题。
    所谓动态代理,在院里上可以这样理解。静态代理的代理类,是事先编写好的,编译器编译成字节码,再由类加载器加载、使用。而动态代理是在运行时,由程序来根据字节码规则生成二进制字节码,然后之类类加载器加载。
    代理类,既然作为代理,他起码就要提供和被代理类一样的方法,让客户端尽量透明的使用具体功能。Java中限制这种一致性的方式有两种:
  • 继承相同的接口: JDK使用的方案
  • 代理类集成被代理类:cglib的方案
 
JDK
 
    JDK提供的动态代理类位于java.lang.reflect包下,主要包含了两个类:
  • public interface InvocationHandler。它只定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。使用中,我们需要提供一个该接口的实现,invoke方法内即可编写我们代理要实现的功能。第一个参数是代理类,第二个是调用的方法,第三个是参数列表。
  • Proxy类。代理类,在运行时动态创建。作为被代理对象的代理。它还包含两个静态方法:
    • Class getProxyClass(ClassLoader loader, Class[] interfaces).该方法可以返回一个代理类。参数一为类加载器,参数二为被代理类的所有接口。该方法生成class的二进制数据,然后通过classLoader加载成类。
    • Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h).该方法返回一个代理类对象。第三个参数为上面说的handler,其中实现代理类的处理。通过反射调用上述方法生成类的构造方法,实例化一个对象。
    例子:
public interface People {
    public void say(String s);
}
public class End implements People {
    public void say(String s) {
        System.out.println("end is saying : " + s);
    }
}
public class EndInvokeHandler implements InvocationHandler {
    private People p;
    public Object getProxy(Class clz) {
        return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
    }
    public EndInvokeHandler(People p) {
        this.p = p;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before end say, gusse he will say : " + (String) args[0]);
        method.invoke(p, args);
        System.out.println("after end say");
        return null;
    }
}
public class TestDynamicProxy {
    public static void main(String[] args) {
        End end = new End();
        EndInvokeHandler handler = new EndInvokeHandler(end);
        People people = (People) handler.getProxy(end.getClass());
        people.say("hahaha!");
    }
}

输出:

before end say, gusse he will say : hahaha!
end is saying : hahaha!
after end say

  

缺点:  被代理的类需要实现至少一个接口,否则就和代理无缘。
 
cglib
 
    前面说过JDK要求被代理的类需要实现至少一个接口,而cglib用的另外一种方案:继承。原理差别不大,直接看例子。
    
public class End {
    public void say(String s) {
        System.out.println("end is saying : " + s);
    }
}
public class EndInteceptor implements MethodInterceptor {
    public Object getProxy(Class clz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before say, i guess he will say : " + objects[0]);
        methodProxy.invokeSuper(o, objects);
        System.out.println("after end say");
        return null;
    }
}
public class TestCglib {
    public static void main(String[] args) {
        EndInteceptor inteceptor = new EndInteceptor();
        End endProxy = (End) inteceptor.getProxy(End.class);
        endProxy.say("hello");
    }
}

输出:

before say, i guess he will say : hello
end is saying : hello
after end say

    其中MethodInterceptor与jdk中的InvocationHandler是一样的功能。在里面调用被代理的方法时,注意是用方法代理MethodProxy的invokeSuper方法。

    由于cglib基于继承机制,所以也有他的限制:不能是final类,final方法也不能被代理。

转载于:https://www.cnblogs.com/endlu/p/5171546.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值