动态代理

来源:互联网 发布:手机淘宝哪里实名认证 编辑:程序博客网 时间:2024/06/05 06:34

代理模式

1.静态代理


使用方法:代理类和被代理的类共同实现一个接口(拥有共同的行为),然后在代理类中有一个被代理类对象的属性,代理类的方法体调用被代理类的方法。

应用场景:

(1)远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

(2)虚拟代理,根据需要创建开销很大的对象。

(3)安全代理,控制真是对象访问时的权限

(4)智能指引,当调用真实的对象时,代理处理另外一些事

代码实现:

1.Subject接口

public interface Subject {    void Request();}

2.代理类,实现接口

public class Proxy implements Subject{    private RealSubject subject;    public void Request() {        if(subject==null){            subject=new RealSubject();        }        subject.Request();    }}

3.委托类

public class RealSubject implements Subject{    public void Request() {        System.out.println("真实的请求");    }}

测试类

public class Main {    public static void main(String[]args){        Proxy proxy=new Proxy();        proxy.Request();    }}

输出:

真实的请求

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

2.动态代理

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

JDK动态代理中包含一个类和一个接口

InvocationHandler接口

public interface InvocationHandler {    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;}

参数说明

(1)proxy:被代理类

(2)Method:要调用的方法

(3)Object[] args:调用方法所需的参数

可以将InvocationHandler接口的子类当做成一个代理类

Proxy类:

Proxy类是专门完成代理的操作类

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException {};

参数说明:

ClassLoader loader:类加载器

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

InvocationHandler h:InvocationHandler接口的子类实例

与静态代理形成对照的是动态代理,动态代理类的字节码在程序运行时由java反射机制动态生成,无需程序员手工编写他的源码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理。java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理的能力

jdk动态代理实现

subject接口:

public interface Subject {    public void request();}

subject实现类:

public class SubjectImpl implements Subject {    @Override    public void request() {        System.out.println("真实的请求");    }}

动态代理类:

public class SubjectProxy implements InvocationHandler {    public Object target;    /*     * 绑定委托对象,并返回一个代理类     */    public Object bind(Object target){        this.target=target;        /*         *Proxy.newProxyInstance(loader, interfaces, h)         *loader:类加载器         *interfaces:委托类的接口,这也是JDK代理的缺点--委托类一定要实现一个接口         *h:InvocationHandler接口的实现类         */        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        System.out.println("事物的开始");        method.invoke(target, args);        System.out.println("事物的结束");        return null;    }}

测试类:

public class Main {    public static void main(String[] args){        SubjectProxy proxy=new SubjectProxy();        Subject subject = (Subject) proxy.bind(new SubjectImpl());        subject.request();    }}

结果:

事物的开始真实的请求事物的结束

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

cglib实现动态代理

委托类(没有实现接口):

public class SubjectImpl {    public void request(){        System.out.println("真实的请求");    }}

cglib代理类:

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

测试类:

public class Main {    public static void main(String[] args) {        SubjectProxy proxy=new SubjectProxy();        SubjectImpl subjectImpl=(SubjectImpl) proxy.getInstance(new SubjectImpl());        subjectImpl.request();    }}

结果:

事物开始真实的请求事物结束
0 0
原创粉丝点击