代理模式


静态/动态 代理模式

为什么要学习代理模式,因为AOP的底层机制就是动态代理!

代理模式:

  • 静态代理
  • 动态代理

学习AOP之前 , 我们要先了解一下代理模式!


静态代理(1)

静态代理角色分析

  • 抽象角色 : 一般使用接口或者抽象类来实现
  • 真实角色 : 被代理的角色
  • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
  • 客户 : 使用代理角色来进行一些操作 .

接口

public interface Rent {

    public void rent();
}

真实角色

public class Host implements Rent {

    @Override
    public void rent() {
        System.out.println("rent my house!");
    }
}

代理角色

public class Proxy implements Rent{

    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        host.rent();
        seeHouse();
        fare();
        contract();
    }

    public void seeHouse(){
        System.out.println("see house!");
    }

    public void fare(){
        System.out.println("give me money!");
    }

    public void contract(){
        System.out.println("sign contract!");
    }
}

客户端访问

public class Client {

    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }

}

输出

rent my house!
see house!
give me money!
sign contract!

静态代理(2)

抽象角色, 抽象起来就是增删改查!

public interface UserService {
    void add();

    void delete();

}

真实角色

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("add one client");
    }

    @Override
    public void delete() {
        System.out.println("delete one client");
    }
}

代理角色

代理角色的好处是业务扩展时,不必修改原有业务层代码,只需要修改代理业务层代码即可。

public class UserServiceImplProxy implements UserService {

    UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    //日志方法
    public void log(String msg){
        System.out.println("used "+msg+" method");
    }
}

客户访问

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceImplProxy proxy = new UserServiceImplProxy();
        proxy.setUserService(userService);

        proxy.add();
        proxy.delete();
    }

}

输出

used add method
add one client
used delete method
delete one client

我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想。AOP: Aspect Oriented Programming,面向切面编程.


静态代理小结

静态代理的好处:

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .

缺点 :
类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !


动态代理(1)

  • 动态代理的角色和静态代理的一样 .
  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
    • 基于接口的动态代理—-JDK动态代理
    • 基于类的动态代理–cglib
    • 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist

我们这里使用JDK的原生代码来实现,其余的道理都是一样的!

JDK的动态代理需要了解两个类 InvocationHandler 和 Proxy

抽象角色

public interface Rent {

    void rent();
}

真实角色

public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("chuzu");
    }
}

代理角色

public class ProxyInvocationHandler  implements InvocationHandler {

    //被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        seeHouse();
        //动态代理的本质,就是利用反射实现
        //通过invoke() 自动实现接口方法
        Object result = method.invoke(rent,args);
        fare();
        return result;
    }


    public void seeHouse(){
        System.out.println("see house!");
    }

    public void fare(){
        System.out.println("fare!");
    }

}

客户访问

public class Client {

    public static void main(String[] args) {
        //真实角色
        Host host = new Host();

        //获取代理工具
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        pih.setRent(host);
        Rent proxy1 = (Rent) pih.getProxy();     //动态生成代理角色
        proxy1.rent();
    }

}

输出

see house!
chuzu
fare!

动态代理(2)

==每个代理实例都有一个关联的调用处理程序。== 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

获取代理类

public class ProxyInvocationHandller implements InvocationHandler {


    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        log(method.getName());      //反射
        //动态代理的本质,就是利用反射实现
        //通过invoke() 自动实现接口方法
        Object result = method.invoke(target,args);
        return result;
    }

    public void log(String msg){
        System.out.println("调用了 "+msg+" 方法");
    }

}

客户访问

注意:动态代理,代理的是接口,不是具体实现类

public class Client {

    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();

        //代理角色
        ProxyInvocationHandller pih = new ProxyInvocationHandller();

        pih.setTarget(userService);     //设置要代理的对象

        UserService proxy = (UserService) pih.getProxy();   //动态生成代理类,proxy 代理了 UserService
        proxy.add();
    }
}

输出

调用了 add 方法
add one client

动态代理小结

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .
  • 一个动态代理 , 一般代理某一类业务
  • 一个动态代理可以代理多个类,代理的是接口!

文章作者: Hailong Gao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hailong Gao !
评论
  目录