您的当前位置:首页正文

Spring(十)代理模式和jdk动态代理的例子

来源:华佗健康网

代理模式是一种常用的设计模式,主要是为了解耦合度和增加类的功能。

我们给出以下场景,我们写了一个类,并且已经运行几个月了,这个时候我们想要增强一下它的功能,并且不破坏原代码,就需要代理模式了。

代理模式有三个类  接口   目标类    代理类  代理类和目标类都要实现接口的方法,并且代理类要调哟目标类的方法,依次可以解耦合并且提供代码的复用性。

给出类子如下

首先我们给出一个接口  Role,并且有三个方法

public interface Role {
    public  void   address();
    public  void   skill();
    public  void   name();
    
}

这就是接口

然后我们写一个类来实现接口,并且给出返回的方法

public class Huiliyi  implements  Role   {
    @Override
    public void address() {
        System.out.println("东京");
    }

    @Override
    public void skill() {
        System.out.println("审判");
    }

    @Override
    public void name() {
        System.out.println("绘梨衣");
    }
}

并且通过程序运行一下

public class main {

    public static void main(String[] args) {
        Role   hui  = new Huiliyi();
        hui.name();
        hui.address();
        hui.skill();
    }
}

结果如下

绘梨衣
东京
审判

那么此时,我们想要增强一下这个类的方法,那么我们就可以这样做

public void address() {
    System.out.print("增强这个方法");
    System.out.println("东京");
}

结果如下       增强这个方法东京

但问题是这样就违反了OCP原则,修改了源码,那么我们可以新建一个类继承这个类,在新建的类中完成代码增强:如下

public class zengqiang  extends Huiliyi {
    public void name() {
        System.out.print("最温暖的");
        System.out.println("绘梨衣");
    }
}
public class main {

    public static void main(String[] args) {
        Role   hui  = new zengqiang();
        hui.name();
    }
}

但问题是这样会导致 类爆炸 ,并且代码的复用性比较低一下 。因此我们可以新写一个类,通过属性的方式来增强

public class zengqiang  implements  Role {
    private   Huiliyi  huiliyi;

    public zengqiang(Huiliyi huiliyi) {
        this.huiliyi = huiliyi;
    }

    @Override
    public void address() {
        System.out.print("天空树");
           huiliyi.address();
    }

    @Override
    public void skill() {
        System.out.print("无情的");
        huiliyi.skill();
    }
    @Override
    public void name() {
        System.out.print("温暖的");
        huiliyi.name();
     }
}

那么我们的测试类应该是

public class main {

    public static void main(String[] args) {
         Huiliyi huiliyi = new Huiliyi();
         Role  zengqiang =  new zengqiang(huiliyi);
         zengqiang.skill();
         zengqiang.name();
         zengqiang.address();
    }
}

并且可以输出对应的结果。

这就是静态代理,通过低耦合的方式来增强原有的类,但是静态代理会导致类爆炸,如果类多的话我们需要重写大量的方法,并且保存在硬盘上。

所幸,我们有动态代理技术,并不需要我们在手写多余的步骤,我们只需要写一下  增强代码部分

接下来还是上面的例子来介绍一下动态代理

动态代理是由jdk完成(我们只介绍jdk方式,当然还有别的jar包提供,但我不在记录)

在程序运行时在内存中动态生成代理类的字节码,然后执行,并不会在硬盘上留下痕迹

public class main {

    public static void main(String[] args) {
//     创建目标对象
   Role  hui =  new Huiliyi();
//        创建代理对象                     类加载器    代理类要实现的接口    调用处理器
        /*   new Proxy.newProxyInstance  ---->创建代理类对象
        * 我们要在代理类中使用 目标类的方法,必须创建出目标类,那么就必须需要获得原来的类加载器,创建对象
        * 代理类要实现的接口其实就是接口类,面向接口编程可以降低耦合度
        * 调用处理器是我们增强的代码部分
        * */
        zengqiang zengqiang = new zengqiang();
         Role proxy =   (Role)  Proxy.newProxyInstance(hui.getClass().getClassLoader(), hui.getClass().getInterfaces(), zengqiang);
//        调用代理方法
          proxy.name();
          proxy.address();
    }
}
public class zengqiang  implements InvocationHandler {
    /*
    * 用来写增强代码
    * 当代理对象调用代理方法的时候,注册在代理处理器中的invoke会被调用,自动调用
    * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.print("温柔的");
        return null;
    }
}

只要代理类调用代理方法,就会调用invokef方法,但是这样只会调用invoke方法,不会调用目标类的目标方法。

java会自动调用实现接口的代理类的代理方法 ----->需要在代理类中完成目标方法的使用  ,看一看invoke的三个参数

完善的代理类如下

    /*
    * 用来写增强代码
    * 当代理对象调用代理方法的时候,注册在代理处理器中的invoke会被调用,自动调用
    * Object proxy  代理类
    * Method method   目标方法
    * Object[] args   目标方法上的实参
    * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.print("温柔的");
      Object r =   method.invoke(target,args);

        return null;
    }

我们先要有一个目标对象 ,然后 调用目标对象的方法,完成使用目标对象。

总结一下代理类的全部过程。

首先我们有个类,需要动态代理增强方法,首先要创建代理类对象,调用jdk的

Proxy.newProxyInstance();

分别传入  目标类加载器  接口方法   代理器

然后我们需要写代理器实现InvocationHandler接口 重写invoke方法,在调用代理类的代理方法的时候会自动调用invoke ,同时为了使用目标类的目标方法,需要创建目标类 并且进行赋值,最后完成动态代理。

 

 

因篇幅问题不能全部显示,请点此查看更多更全内容