Java 动态代理(JDK&CGLib)

来源:互联网 发布:unity3d 模型闪烁 编辑:程序博客网 时间:2024/05/22 12:23

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
按照代理的创建时期,代理类可以分为两种:

  1. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
  2. 动态代理: 与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

一、静态代理
代码实现
Request.java类
package com.xxx.proxy;public interface Request {public void request();}

HttpRequest.java类
package com.xxx.proxy;public class HttpRequest implements Request {@Overridepublic void request() {System.out.println("http request......");}}

RequestProxy.java类
package com.xxx.proxy;/** * 委托类(静态代理) * @author bingbing feng * */public class RequestProxy implements Request{private Request req;//被代理的类public void buildProxy(Request req){this.req = req;}@Overridepublic void request(){//调用之前        doBefore();req.request();// 调用之后        doAfter();}private void doAfter() {System.out.println("after method invoke");}private void doBefore() {System.out.println("before method invoke");}}


每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

二、动态代理
1、使用JDK动态代理
java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力,具体请参看JDK文档

实现代码
JDKProxy.java 类
package com.xxx.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JDKProxy implements InvocationHandler{private Object target;public Object createProxy(Object target){this.target = target;return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}/** * @param proxy * 被代理的类 * @param method * 要调用的方法  * @param args * 方法调用时所需要的参数  * 可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject */@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {Object retVal = null;  // 调用之前        doBefore();retVal = method.invoke(target, args);// 调用之后        doAfter();return retVal;}private void doAfter() {System.out.println("after method invoke");}private void doBefore() {System.out.println("before method invoke");}}


2、使用CGLib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
原理:用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数:
public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)

 在intercept()函数里,你可以在执行Object result=proxy.invokeSuper(o,args);来执行原有函数,在执行前后加入自己的东西,改变它的参数值等等。

注意:在使用CGLIB时需引入cglib-nodep-2.1_3.jar包

实现代码
Student.java类
package com.xxx.proxy;public class Student {public void doSomeThing(){System.out.println("day day study,day day up...");}}

CGLibProxy.java类
package com.xxx.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * 通过CGLib实现动态代理 * @author bingbing feng * */public class CGLibProxy implements MethodInterceptor{//要代理的原始对象    private Object obj;    private Enhancer enhancer=new Enhancer();    public Object createProxy(Object target){this.obj = target;enhancer.setSuperclass(this.obj.getClass());// 设置代理目标        enhancer.setCallback(this);// 设置回调        enhancer.setClassLoader(target.getClass().getClassLoader());        return enhancer.create();}/**     * 在代理实例上处理方法调用并返回结果     *      * @param proxy     *            代理类     * @param method     *            被代理的方法     * @param params     *            该方法的参数数组     * @param methodProxy     */@Overridepublic Object intercept(Object proxy, Method method, Object[] params,MethodProxy methodProxy) throws Throwable {Object result = null;        // 调用之前        doBefore();        // 调用原始对象的方法        result = methodProxy.invokeSuper(proxy, params);        // 调用之后        doAfter();        return result;}private void doAfter() {System.out.println("after method invoke");}private void doBefore() {System.out.println("before method invoke");}}


测试代码
ProxyTestMain.java类
package com.xxx.proxy;/** * 测试类 * @author bingbing feng * */public class ProxyTestMain {/** * @param args */public static void main(String[] args) {testStaticProxy();//testJDKProxy();//testCGLibProxy();}private static void testStaticProxy() {Request req = new HttpRequest();RequestProxy proxy = new RequestProxy();proxy.buildProxy(req);proxy.request();}private static void testCGLibProxy() {Request req = new HttpRequest();JDKProxy proxy = new JDKProxy();Request reqProxy = (Request) proxy.createProxy(req);reqProxy.request();}private static void testJDKProxy() {Student stu = new Student();CGLibProxy proxy = new CGLibProxy();Student stuProxy = (Student) proxy.createProxy(stu);stuProxy.doSomeThing();}}


运行结果
before method invoke
http request......
after method invoke





原创粉丝点击