Java 的静态代理和动态代理

来源:互联网 发布:燕大图书馆网络 编辑:程序博客网 时间:2024/06/05 08:42

一、代理概念:Proxy代理模式是一种结构型设计模式,其目的就是为其他对象提供一个代理以控制对该对象的访问。代理类和委托类有共同的父类或接口,这样在任何使用委托类对象的地方动可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完后的后续处理。

二、静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

静态类的优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共同有点。

静态代理缺点:1代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。2代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

package proxy;/** * 代理接口,用于定义要执行的任务 * @author 21409262 * */public interface Subject {/** * 需要执行的任务 */public  void task(String taskName);}package proxy;/** * 真正执行任务的类,实现了代理接口的方法 * @author 21409262 * */public class RealSubject implements Subject {@Overridepublic void task(String taskName) {// TODO Auto-generated method stubSystem.out.println("正在执行任务: "+taskName);}}package proxy;/** * 静态代理类,实现了了代理接口 * @author 21409262 * */public class StaticProxySubject implements Subject {/** * 代理类持有一个委托类的对象引用 */    private Subject delegate;         public StaticProxySubject(Subject delegate){    this.delegate = delegate;    }        /**     * 代理类先执行预处理命令,再将请求执行的任务分派给委托类,委托类执行完任务后,再做后续处理     */@Overridepublic void task(String taskName) {// TODO Auto-generated method stubSystem.out.println("执行任务前,预处理...");//调用委托类执行任务delegate.task(taskName);System.out.println("执行任务后,后续处理...");}}

三、动态代理:动态代理类的字节码在程序运行时有Java反射机制动态生成,无需成员编写他的源代码。

优点:动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展行,因为Java反射机制可以生成任意类型的动态代理类对象。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力

缺点:JDK的动态代理依靠接口实现,如果有些累没有实现接口,则不能使用JDK代理,这就要使用CGLib的动态代理了。

 

package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * Jdk 自带的动态代理 */public class JavaDynamicProxySubject implements InvocationHandler {//代理类持有个一委托类对象private Object target;//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。                  public Object newProxyInstance(Object target){          this.target=target;          //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例            //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器          //第二个参数要实现和委托类对象一样的接口,所以只需要拿到委托类对象的实现接口          //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法          //根据传入的委托类对象返回一个代理对象          return Proxy.newProxyInstance(target.getClass().getClassLoader(),          target.getClass().getInterfaces(),this);      }       //关联的这个实现类的方法被调用时将被执行  @Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {              Object ret=null;          try{              /*原对象方法调用前处理日志信息*/         System.out.println("执行任务之前的预处理...");                     //调用目标方法              ret=method.invoke(target, args);                         /*原对象方法调用后处理日志信息*/              System.out.println("执行任务之后的后续处理...");          }catch(Exception e){              System.out.println("执行任务时出现异常...");              throw e;          }          return ret;  }}

CGLIB代理:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

缺点:GLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

</pre><pre name="code" class="html"><pre name="code" class="html"><span style="font-size:18px;">package proxy;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 CGLibDynamicProxySubject implements MethodInterceptor {private Object target;/**      * 创建代理对象      *       * @param target      * @return      */      public Object getInstance(Object target) {          this.target = target;          Enhancer enhancer = new Enhancer();          enhancer.setSuperclass(this.target.getClass());          // 回调方法          enhancer.setCallback(this);          // 创建代理对象          return enhancer.create();      }          /**     * intercept()方法拦截所有目标类方法的调用,     * obj表示目标类的实例,     * method为目标类方法的反射对象,     * args为方法的动态入参,     * proxy为代理类实例。     * proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。     */@Overridepublic Object intercept(Object obj, Method method, Object[] arg,MethodProxy proxy) throws Throwable {// TODO Auto-generated method stubSystem.out.println("执行任务前,预处理...");          proxy.invokeSuper(obj, arg);          System.out.println("执行任务后,后续处理...");          return null;  }}</span>
<span style="font-size:18px;"></span>
<span style="font-size:18px;"></span>
package proxy;public class TestProxy {public static void main(String[] args) {//定义委托类对象Subject subject = new RealSubject();//将委托类对象做为参数传入代理类,创建代理类对象/*Subject proxy = new StaticProxySubject(subject);//代理类对象执行委托类对象的任务proxy.task("拯救A股");*/CGLibDynamicProxySubject cglib=new CGLibDynamicProxySubject();  //根据代理类获得具体的代理对象RealSubject subject1=(RealSubject)cglib.getInstance(subject);  subject1.task("拯救A股");}}



0 0
原创粉丝点击