java代理模式

代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能

举例说明:小张发现妻子出轨想要离婚,于是找法院提出离婚,由于缺乏相关法律知识,法院没通过,于是小张聘请了代理人律师,由律师根据所学的法律条案向法院提出离婚,最终通过实现了离婚。在这里小张提出离婚是目标对象,律师是代理对象,律师采用的所学的法律知识就是增强额外的功能。

接下来我们用静态代理代码在实现上面的故事:

1.静态代理

//接口类(目标动作)
interface event{
 public void divorce();//离婚
}
//目标实现类(实现目标动作)=>张三要求离婚
class Xiaozhang implements event{
    @Override
    public void divorce() {
        System.out.println("老婆出轨,我要离婚");
    }
}
//代理类(实现目标动作)=>代理律师用所学法律增加张三提出离婚的可行性
class Staticlawyer implements event{
   private Xiaozhang xiaozhang;
   public Staticlawyer(Xiaozhang xiaozhang){
       this.xiaozhang=xiaozhang;
   }
    @Override
    public void divorce() {
        System.out.println("根据法律条文");
        xiaozhang.divorce();
        System.out.println("根据道理伦理");
    }
}

public class StaticPropxy {
    public static void main(String[] args) {
        Staticlawyer staticlawyer=new Staticlawyer(new Xiaozhang());
        staticlawyer.divorce();
    }

}
    

输出:

java代理模式_第1张图片 

总结:
静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。

故事的发展:在这里我们可以看到在静态代理中,目标对象和代理对象都要实现接口类,但是问题随着来着,随着小张的离婚成功,小张一个人寂寞难耐,跑去嫖娼了,正好被警察逮到了,这时候小张又得求助他的代理律师来捞他,那么如何用代码来实现后续的故事,大家肯定想到在接口类再加个接口,我们来实现下

//接口类(目标动作)
interface event{
    public void divorce();//离婚
    public void crime();//犯罪
}

//目标实现类(实现目标动作)
class Xiaozhang implements event{
    @Override
    public void divorce() {
        System.out.println("老婆出轨,我要离婚");
    }

    @Override
    public void crime() {
        System.out.println("我只是跟她一起学英语,没有嫖娼");
    }
}
//代理类(实现目标动作)
class Staticlawyer implements event{
   private Xiaozhang xiaozhang;
   public Staticlawyer(Xiaozhang xiaozhang){
       this.xiaozhang=xiaozhang;
   }
    @Override
    public void divorce() {
        System.out.println("根据法律条文");
        xiaozhang.divorce();
        System.out.println("根据道理伦理");
    }

    @Override
    public void crime() {
        System.out.println("根据法律条文");
        xiaozhang.crime();
        System.out.println("根据道理伦理");
    }
}

public class StaticPropxy {
    public static void main(String[] args) {
        Staticlawyer staticlawyer=new Staticlawyer(new Xiaozhang());
        staticlawyer.crime();
    }

}

结果:

java代理模式_第2张图片

有没有发现我们的代码,在遇到这种小张这种要求多的时候,如果再继续用静态代理去处理张三的故事,就会增加代码维护成本,暴露出了缺点了

不足:静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的实现,增加维护成本

那我们就来学习我们的JDK动态代理

2.JDK动态代理

着这里我们要用到Propxy来动态生成我们的代理对象
Proxy对象的生成利用JDK的Api,在JVM内存中动态的构建Proxy对象。

java代理模式_第3张图片

在这里我们对Proxy.newProxyInstance的方法参数进行解释
@param loader 类加载器用于定义代理类
@param interfaces 接口代理类的接口列表(要实现指定的接口)
@param 实现InvocationHandler的代理对象实例
@返回具有指定调用处理程序的代理实例,由指定的类加载器定义的代理类 实现指定的接口

我们先实现代理的对象:

class JdkLawyer implements InvocationHandler {
    private Xiaozhang xiaozhang;
    public JdkLawyer(Xiaozhang xiaozhang){
        this.xiaozhang=xiaozhang;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        /*
    *
    * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
    * method:我们所要调用目标对象的具体方法(这里就是通过反射获取Xiaozhang类中的method)
    * args:代理对象方法传递的参数

    * */
        System.out.println("根据法律条文");
        Object invoke=method.invoke(xiaozhang,args);//通过反射执行目标对象方法
        System.out.println("根据道理伦理");
        return invoke;
    }
}

采用Propxy的newProxyInstance来动态生成代理对象

public class JdkPropxy {
    /*
@param loader 类加载器用于定义代理类
@param interfaces 接口代理类的接口列表(要实现指定的接口)
@param 实现InvocationHandler的代理对象实例
@返回具有指定调用处理程序的代理实例,由指定的类加载器定义的代理类 实现指定的接口
     */
    public static void main(String[] args) {
        event e= (event) Proxy.newProxyInstance(JdkPropxy.class.getClassLoader(),new Class[]{event.class},new JdkLawyer(new Xiaozhang()));
        e.crime();
    }
}

结果:java代理模式_第4张图片

总结:jdk动态代理通过Proxy的 newProxyInstance生成代理类,通过调用接口中的方法名,在代理类中调用增强后的目标方法

在这里我们可以看到动态代理是基于接口的一种代理,那么如果我们没有定义这个接口类还能不能用代理,答案是也可以,接下来介绍我们的cglib代理

3.cglib代理

这里先介绍下cglib代理的原理:

CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理,那么CGlib动态代理的精神就是继承,因为采用的是继承,所以不能对final修饰的类进行代理.如果目标方法被final修饰,那么就不能进行重写,只能继承
class Xiaozhang{

    public void divorce() {
        System.out.println("老婆出轨,我要离婚");
    }


    public final void crime() {
        System.out.println("我只是跟她一起学英语,没有嫖娼");
    }
}


class cglibLawer implements MethodInterceptor {

    private Object target;
    public Object getInstance(Object target){
        //要代理的原始对象
        this.target = target;
        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 设置代理目标:为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(this.target.getClass());
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而CallBack则需要实现intercept()方 法进行拦截
        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 static void main(String[] args) {
//        event e= (event) Proxy.newProxyInstance(JdkPropxy.class.getClassLoader(),new Class[]{event.class},new JdkLawyer(new Xiaozhang()));
//        e.crime();

        //cglib代理
        Xiaozhang li=new Xiaozhang();
        cglibLawer c=new cglibLawer();
        Xiaozhang lisiproxy= (Xiaozhang) c.getInstance(li);
        lisiproxy.crime();
    }

到这里我们就学到了java中的三种代理的模式

你可能感兴趣的:(spring,spring,java)