码迷,mamicode.com
首页 > 其他好文 > 详细

代理模式

时间:2018-10-28 14:51:05      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:static   事件   spring   动态代理   加载   扩展   第一个   处理器   create   

  代理模式是通过代理对象来访问目标对象中的方法,通过这种方式,我们可以增强目标对象的方法(符合开闭原则),代理模式分为静态代理和动态代理两种。

1. 静态代理,首先我们需要有一个接口,实现接口的目标对象和代理对象

/**
 * created by xushilong on 2018/10/25.
 */
public interface IShape {
    String createShape();
}
/**
 * created by xushilong on 2018/10/25.
 */
public class Circle implements IShape {
    @Override
    public String createShape() {
        return "circle";
    }
}
/**
 * created by xushilong on 2018/10/25.
 */
public class CircleProxy implements IShape{

    private IShape target;

    public CircleProxy(IShape target) {
        this.target = target;
    }

    @Override
    public String createShape() {
        return "big " + target.createShape();
    }
}

从代码中可以看出,有一个IShape接口以及实现了该接口的Circle类,而我们的代理对象也实现了该接口,并且有一个目标对象,通过构造方法来初始化这个目标对象,然后就可以使用createShape()方法来对目标对象的方法进行增强了。通过这种方法我们可以在不修改目标对象的情况下来对目标对象的方法进行扩展,但是因为代理对象和目标对象都实现了接口,一旦接口改动,目标对象和代理对象都需要改动,维护起来较为麻烦。

2. 动态代理

2.1 JDK动态代理

动态代理的代理对象是通过Java反射技术拿到目标对象的类加载器并且创建目标对象的实例,然后目标对象的方法执行时触发事件处理器的方法,通过重写事件处理器的方法我们可以在目标对象的方法执行前后来进行一些额外的操作,这样同样达到了增强目标对象方法的效果,而且代理对象不需要实现目标对象的接口。

首先我们来说一下使用JDK生成代理对象的方法

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

其中,第一个参数是目标对象的类加载器,它定义了由哪个类加载器来对代理对象进行加载,第二个参数是目标对象所实现的接口(这个参数的作用网上有讲解),第三个参数英文翻译“调用处理者”,当目标对象的方法调用时,这个方法的调用就会转发由InvocationHandler这个接口的invoke来进行调用,我们来查看InvocationHandler这个接口的唯一方法invoke();

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

其中第一个参数是我们的目标对象,第二个参数时目标对象所调用的哪个方法,第三个参数是这个方法所需要的参数。JDK生成代理对象的方法介绍完了,我们可以来实现生成代理对象的方法了。

/**
 * created by xushilong on 2018/10/25.
 */
public class CircleDynamicProxy {

    private Object target;

    public CircleDynamicProxy(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return  "big " + method.invoke(target,args);
                    }
                });
    }
}

 2.2 cglib动态代理

JDK动态代理的实现必须要求目标对象实现了接口,但是有的时候我们的目标对象并没有实现接口,这个时候我们可以通过cglib来生成代理对象。使用cglib需要引入jar包,但是spring核心包中已经包含了cglib的功能,所以我们只需要引入spring-core.jar就好了。

/**
 * created by xushilong on 2018/10/28.
 */
public class Square {

    public String createSquare() {
        return "square";
    }
}
/**
 * created by xushilong on 2018/10/28.
 */
public class SquareDynamicProxy implements MethodInterceptor {

    private Object target;

    public SquareDynamicProxy(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return "big " + method.invoke(target,objects);
    }
}

需要注意的是,cglib也叫子类代理,它的原理实际上是在内存中构建一个子类对象来实现对目标对象方法的扩展,因此我们的目标对象如果想要使用cglib实现动态代理,那么目标对象就不能为final。同样,目标对象的方法也不能为final或者static。

代理模式

标签:static   事件   spring   动态代理   加载   扩展   第一个   处理器   create   

原文地址:https://www.cnblogs.com/xslzjbra/p/9853200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!