JavaJDK Proxy与CGLib的区别<转>

来源:互联网 发布:淘宝店铺站外引流免费 编辑:程序博客网 时间:2024/05/22 15:04

1、什么是代理?

2、静态代理与动态代理

3、静态代理实例

4、JDK动态代理实例

5、CGLib 简介

CGLib 与JDK动态代理的区别

    代理模式是Java中常见的一种模式,英文名字叫走Proxy或者Surrogate,代理的本意是一个人代表另一个人,或者一个机构代表另一个机构,采取行动,因而,代理和现实生活中的中介有很大的类似,你买房子、卖房子,可以自己去操作,但是需要了解和买卖房产无关的细节,如契税等,而找一个中介,则不用关心这些与买卖房产无直接关系的中间细节,只关心业务本身。

     因而,我们可以把代理模式的适用,总结为:代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

   代理模式的用途,可以分为如下几种:

    1)远程代理(Remote ):为远程对象的invoke提供代理,典型的例子如RMI或者EJB,都会在本地生成一个远程对象的stub。

    2)虚拟代理(Virtual):如果需要创建一个资源消耗大的对象,则可以首先使用一个代理,使这个对象在需要时才真正创建。

    3)Copy-On-Write 代理:把复制延迟到客户端需要时才采取行动

    4)保护(Protect)

    5)Cache代理

   2.静态代理与动态代理

代理分为静态代理和动态代理

   按照代理创建的时期,可以分为动态代理和静态代理:

 静态代理:由程序员或者自动生成工具生成代理类,然后进行代理类的编译和运行。在代理类、委托类运行之前,代理类已经以.class的格式存在。

 静态代理:在程序运行时,由反射机制动态创建而成。

 3.静态代理实例

    静态代理实例:

     首先需要一个接口:

/** 

 * 定义一个账户接口 

 * @author Administrator 

 */  

public interface Count {  

    // 查看账户方法  

    public void queryCount();  

  

    // 修改账户方法  

    public void updateCount();  

  

}  

  然后是委托类,也就是接口的真正实现类,内涵主要的业务逻辑:

/** 

 * 委托类(包含业务逻辑) 

 * @author Administrator 

 */  

public class CountImpl implements Count {  

    @Override  

    public void queryCount() {  

        System.out.println("查看账户方法...");  

    }  

    @Override  

    public void updateCount() {  

        System.out.println("修改账户方法...");  

    }  

}  

   最后是代理类: 

/** 

 * 这是一个代理类(增强CountImpl实现类) 

 *  

 * @author Administrator 

 *  

 */  

public class CountProxy implements Count {  

    private CountImpl countImpl;  

  

    /** 

     * 覆盖默认构造器 

     *  

     * @param countImpl 

     */  

    public CountProxy(CountImpl countImpl) {  

        this.countImpl = countImpl;  

    }  

  

    @Override  

    public void queryCount() {  

        System.out.println("事务处理之前");  

        // 调用委托类的方法;  

        countImpl.queryCount();  

        System.out.println("事务处理之后");  

    }  

  

    @Override  

    public void updateCount() {  

        System.out.println("事务处理之前");  

        // 调用委托类的方法;  

        countImpl.updateCount();  

        System.out.println("事务处理之后");  

  

    }  

  

}  

运行:

public class CountTest {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        CountImpl countImpl = new CountImpl();    

        CountProxy countProxy = new CountProxy(countImpl);    

        countProxy.updateCount();    

        countProxy.queryCount();   

  

    }  

  

}  

  从静态代理中可以看出:

    1.接口:代理类需要实现一个接口,这个接口和委托类的接口是一样的,这样proxy才能和委托类行为表现一致

    2. 方法(Method):由于接口限制,proxy类中也要有interface中的各个方法,这就造成了代码重复

4.JDK动态代理实例

    动态代理类克服了proxy需要继承专一的interface接口,并且要实现相应的method的缺陷。从JDK 1.3以来,Java 语言通过java.lang.reflex库提供的三个类直接支持代理:

     java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler 和Method.

    Proxy类在运行时动态创建代理对象,这也是dynamic proxy的由来,下面是类图,其中最重要的是newProxyInstance,这个方法中,指明了将要代理的类的加载器,业务类接口,以及代理类要执行动作的调用处理器(InvokeHandler)

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 

InvocationHandler h)   throws IllegalArgumentException 

参数说明: 

ClassLoader loader:类加载器 

Class<?>[] interfaces:得到全部的接口 

InvocationHandler h:得到InvocationHandler接口的子类实例 


Ps:类加载器 

在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 

Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 

Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; 

AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 


   当系统有了一个代理对象之后,对原方法的调用会首先被分派到一个调用处理器(Invocation Handler).InvocationHandler 接口如下图所示:



  代码:


    接口:


[java] view plain copy

package com.mahoutchina.pattern.proxy.dynamicproxy;  

  

public interface BookFacade {  

    public void addBook();  

    public void deleteBook();  

}  

  实际业务类:

 


[java] view plain copy

package com.mahoutchina.pattern.proxy.dynamicproxy;  

  

public class BookFacadeImpl implements BookFacade {  

  

    @Override  

    public void addBook() {  

        System.out.println("add book logic is running。。。");   

    }  

  

    @Override  

    public void deleteBook() {  

        System.out.println("delete book logic is running。。。");  

          

    }  

      

  

}  

  动态代理类:

    


[java] view plain copy

package com.mahoutchina.pattern.proxy.dynamicproxy;  

  

import java.lang.reflect.InvocationHandler;  

import java.lang.reflect.Method;  

import java.lang.reflect.Proxy;  

  

public class BookFacadeProxy implements InvocationHandler {  

    private Object target;  

  

    /** 

     *  

     * @param target 

     * @return 

     */  

    public Object bind(Object target) {  

        this.target = target;  

        // 取得代理对象  

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  

                target.getClass().getInterfaces(), this);  

    }  

  

    @Override  

    public Object invoke(Object proxy, Method method, Object[] args)  

            throws Throwable {  

        Object result=null;  

        System.out.println("Proxy start...");  

        System.out.println("method name:"+method.getName());  

        result=method.invoke(target, args);  

        System.out.println("Proxy end...");  

        return result;  

    }  

  

}  

  测试类:

public class TestProxy {  

  

/** 

 * @param args 

 */  

public static void main(String[] args) {  

    BookFacadeProxy proxy = new BookFacadeProxy();  

    BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  

    bookProxy.addBook();  

    bookProxy.deleteBook();  

}  

   对于JDK 的Proxy,有以下几点:

    1)Interface:对于JDK proxy,业务类是需要一个Interface的,这也是一个缺陷


    2)Proxy,Proxy 类是动态产生的,这个类在调用Proxy.newProxyInstance(targetCls.getClassLoader, targetCls.getInterface,InvocationHander)之后,会产生一个Proxy类的实例。实际上这个Proxy类也是存在的,不仅仅是类的实例。这个Proxy类可以保存到硬盘上。


    3) Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来


    4) InvocationHandler: 这个类在业务委托类执行时,会先调用invoke方法。invoke方法再执行相应的代理操作,可以实现对业务方法的再包装


    5 CGLib 简介

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

示例 

   业务类:

public interface BookFacade {  

    public void addBook();  

}  

/** 

 * 这个是没有实现接口的实现类 

 *  

 * @author student 

 *  

 */  

public class BookFacadeImpl1 {  

    public void addBook() {  

        System.out.println("增加图书的普通方法...");  

    }  

}  

  代理:

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 student 

 *  

 */  

public class BookFacadeCglib 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();  

    }  

  

    @Override  

    // 回调方法  

    public Object intercept(Object obj, Method method, Object[] args,  

            MethodProxy proxy) throws Throwable {  

        System.out.println("事物开始");  

        proxy.invokeSuper(obj, args);  

        System.out.println("事物结束");  

        return null;  

    }  

}  


  测试;

import net.battier.dao.impl.BookFacadeImpl1;  

import net.battier.proxy.BookFacadeCglib;  

public class TestCglib {  

    public static void main(String[] args) {  

        BookFacadeCglib cglib=new BookFacadeCglib();  

        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  

        bookCglib.addBook();  

    }  

}  

原文来源:http://blog.csdn.net/hintcnuie/article/details/10954631
0 0