代理模式 -动态代理

来源:互联网 发布:tensorflow 关闭gpu 编辑:程序博客网 时间:2024/04/29 14:24

核心业务与辅助业务写在了一个方法中,不但业务冗余了不说,像开关数据库连接这样的公共操作也大量的重复,这时候就出现了代理模式的思想

Jdk动态代理:

1.如果要实现动态代理,那么你要编写的那个代理类就需要实现一个InvocationHandle接口.这个接口所在位置是java.lang.reflect.InvocationHandler.看到reflect我们就能知道,动态代理肯定是通过反射来实现的了,这个接口中有一个方法:

    Object invoke(Object proxy, Method method, Object[] args) :在代理实例上处理方法调用并返回结果。

    invoke方法其实是反射里边的一个方法,在这个方法中有三个参数:

    Ojbect proxy:表示需要代理的对象

    Method method:表示要操作的方法

    Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)

  2.如果要想让代理设计真正可用,我们还必须有一个代理类对象产生,这有用到了另一个类:java.lang.reflect.Proxy.我的中文jdk文档对他的描述是:

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

  在这个类下面,我们找到了这样一个方法:

  public static Object newProxyInstance(ClassLoader loader,
Class

package com.Proxy.Proxy1;public interface Service {     public void saveToDB();}
package com.Proxy.Proxy1;public class ServiceImpl implements Service{    @Override    public void saveToDB() {        // TODO Auto-generated method stub        System.out.println("save to DB !!!");    }}
package com.Proxy.Proxy1;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JdkServiceProxy implements InvocationHandler {    private Object target =null;   public void Open(){       System.out.println("open database connection!!!");   }    public void Close(){        System.out.println("close database connection!!!");    }    public Object getProxy(Object obj){        this.target=obj;        System.err.println(this);        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        // TODO Auto-generated method stub        Open();        Object result=method.invoke(target, args);//通过反射调用真实业务对象的业务方法,并且返回        Close();        return result;    }}
package com.Proxy.Proxy1;import org.junit.Test;public class Proxy1Test {          @Test           public void testJdk(){               // ServiceImpl service=(ServiceImpl) new ServiceProxy().getProxy(new ServiceImpl());  //Error JDK的动态代理依靠接口实现                Service service=(Service) new JdkServiceProxy().getProxy(new ServiceImpl());                service.saveToDB("s");           }}

Test Result:

open database connection!!!save to DB !!!close database connection!!!

下面来总结一下:

  动态代理和静态代理相比较,最大的好处就是接口中声明的所有的方法都被转移到一个集中的方法中去处理,就是invocke()方法.这样在接口中声明的方法比较多的情况下我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

  动态代理只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法的返回值是被代理接口的一个实现类。

  那么有没有可能我们可以不依赖接口呢?这时候就需要CGLIB实现动态代理了,这个jar包可以让我们摆脱接口的烦恼

参考博客:http://www.cnblogs.com/fingerboy/p/5335328.html

CGlib 动态代理:

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

代理类:

package com.Proxy.Proxy1;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CGlibServiceProxy  implements MethodInterceptor{           private Object target=null;           public Object getProxy(Object target){               this.target=target;               Enhancer enhancer =new Enhancer();               enhancer.setSuperclass(this.target.getClass());               //回调方法                 enhancer.setCallback(this);                 //创建代理对象               return enhancer.create();           }    @Override    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {        // TODO Auto-generated method stub        Open();        proxy.invokeSuper(obj,args);        Close();        return null;    }     public void Open(){           System.out.println("open database connection!!!");       }        public void Close(){            System.out.println("close database connection!!!");        }}

Test:

 @Test           public void testCGlib(){               ServiceImpl serviceImpl=(ServiceImpl) new CGlibServiceProxy().getProxy(new ServiceImpl());               serviceImpl.saveToDB("s");           }

参考博客:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

原创粉丝点击