Java设计模式之代理模式

一、前言

代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,实现对目标功能的扩展。

这涉及到一个编程思想:不要随意去修改别人已经写好的代码或者方法(有坑)。如果需要修改,可以通过代理模式实现。

二、写法实现

代理模式通常有三种实现写法:静态代理、动态代理、Cglib代理。

我们依次说下这三种代理模式:

我们现有 AnimalsDao接口和其实现AnimalsDaoImpl实现类,有两个方法,run和eat。

public interface AnimalsDao {
    //提供两个方法
    void run();
    void eat();
}
public class AnimalsDaoImpl implements AnimalsDao{
    @Override
    public void run() {
        System.out.println("run");
    }

    @Override
    public void eat() {
        System.out.println("eat");
    }
}

现在我们想在run或者eat方法里之前做一些操作。

1.静态代理

public class StaticProxy implements AnimalsDao{

    @Override
    public void run() {
        System.out.println("StaticProxy--------->");
        dao.run();
    }

    @Override
    public void eat() {
        System.out.println("StaticProxy--------->");
        dao.eat();
    }

    private AnimalsDao dao;
    public StaticProxy(AnimalsDao dao){
        this.dao=dao;
    }
}

说明:静态代理通过实现目标对象接口,然后调用相同方法来实现代理。这种方式的缺点显而易见,当目标对象接口方法变动时,直接影响到代理类,需要对代理类进行修改,十分不方便。而且如果目标对象接口方法较多时,代理类也十分臃肿,不便维护。

2.动态代理

public class DynamicProxy {
    //要代理的对象
    private Object obj;
    public DynamicProxy(Object obj){
        this.obj=obj;
    }

    public Object getObjProxyIntance(){
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行目标对象方法
                System.out.println("DynamicProxy--------->");
                return method.invoke(obj,args);
            }
        });
    }
}

说明:动态代理模式主要借助JDK代理对象API  java.lang.reflect.Proxy来实现的,所以也称作JDK代理。我们看一下JDK这个类,其中重要的一个方法如下:

Java设计模式之代理模式_第1张图片

这个方法的三个参数:

ClassLoader loader  目标对象类加载器

Class[] interfaces  目标对象接口类型

InvocationHandler h  事物处理,在这里面可以实现自己想要的逻辑

根据以上,可以看出动态代理实现要求目标对象必须有实现接口。代理类不必实现接口。

3.Cglib代理

要实现Cglib代理,必须引入cglib.jar 包,由于Spring-core包中已经包含了cglib功能,且大部分Java项目均引入了spring 相关jar包,这边使用spring的cglib来讲解。(他俩实现方式都是一样的)

public class CglibProxy implements MethodInterceptor {

    //目标对象
    private Object obj;
    public CglibProxy(Object obj){
        this.obj=obj;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(obj.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CglibProxy--------->");
        return method.invoke(obj,objects);
    }
}

说明:可以看出,Cglib代理模式实现不需要目标对象一定实现接口,故目标对象如果没有实现接口,可以使用cglib代理模式。其实Spring的代理模式也是这么实现的。

四、应用实例

Spring的代理模式:如果容器目标对象有接口,使用JDK动态代理,如果没有接口,使用cglib动态代理。

Java设计模式之代理模式_第2张图片

五、参考资料

1.https://www.cnblogs.com/cenyu/p/6289209.html

2.Spring 4.0 源代码

六、GitHub代码地址

https://github.com/JavaZWT/designPatterns

你可能感兴趣的:(JAVA)