Spring 代理模式 D4

1 代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP和SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

关于代理的举例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhqJCK5O-1605063583227)(Spring%20AOP%20D2.assets/image-20201110144354776.png)]

2 静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色: 代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户: 访问代理对象的人。

我们再举一个例子,MVC模式中,用户访问Controller层,进而Service层,进一步调用dao层实现具体操作。现假设我们已经开发好了一个可以正常运行的代码块(可实现CRUD操作),而客户此时又提出一个新需求:想要追踪方法的调用,即显示日志。

Solution:

面对这样的问题,通常我们想的就是,直接在原来的代码中更改,但是这样做很不安全,可能我们改出了新的功能,旧的功能出现了bug,让问题变得越来越复杂。

此时我们引入代理的思想,不动原来的代码,就像增加了一个代理商一样增加了一个类,通过该类增加功能,同时完成原来的操作,这样做不会影响原来的代码逻辑,可以更好地适应需求变更。

以下代码可以辅助我们理解上面举的例子:

UserService~~接口:

public interface UserService {
    public void insert();
    public void delete();
    public void update();
    public void query();
}

UserServiceImpl~~实现类:

public class UserServiceImpl implements UserService{
    public void insert() {
        System.out.println("增加成员!");
    }
    public void delete() {
        System.out.println("删除成员!");
    }
    public void update() {
        System.out.println("修改成员信息!");
    }
    public void query() {
        System.out.println("查询成员信息!");
    }
}

UserServiceProxy~~代理类:

public class UserServiceProxy implements UserService {
    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }
  
    public void log(String msg) {
        System.out.println("【新增语句】使用了"+msg+"方法");
    }
    public void insert() {
        log("insert");
        userService.insert();
    }
    public void delete() {
        log("delete");
        userService.delete();
    }
    public void update() {
        log("update");
        userService.update();
    }
    public void query() {
        log("query");
        userService.query();
    }
}

Client~~客户类:

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

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService); //代理原先的类
        proxy.update(); //通过代理对象来实现原先的操作
    }
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJCt3yEj-1605063583229)(Spring%20AOP%20D2.assets/image-20201110193637694.png)]

图解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1cogtCd-1605063583232)(Spring%20AOP%20D2.assets/image-20201110194758671.png)]

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共业务放给代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍~开发效率变低。

3 动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是自动生成的,不是我们直接写好的!
  • 动态代理可以分为两大类:基于接口的动态代理;基于类的动态代理
    • 基于接口:JDK动态代理【本文中展示该方法】
    • 基于类:cglib
    • java字节码实现:javassist

举例说明:拿一开始的例子来说明,假设有租客(Client)要租房,而房东(Host)正好要出租,租客和房东都找到了代理中介。我们参照这个故事来编写一个实现动态代理的代码:

Rent~~接口:

public interface Rent {
    public void rent();
}

Host~~房东类:

public class Host implements Rent {
    public void rent() {
        System.out.println("房东出租房屋!");
    }
}

ProxyInvocationHandler~~使用该类自动生成代理类:

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);
    }

    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(rent, args);
        return result;
    }
}

Client~~客户类:

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

        //创建代理角色
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //传入要代理的接口对象!
        pih.setRent(host);

        //获取代理对象!
        Rent proxy = (Rent) pih.getProxy();

        //使用代理对象来完成操作
        proxy.rent();
    }
}

动态代理其实挺简单,需要特别补充的是:

  • 生成代理类Proxy.newProxyInvocation(参数1, 参数2, 参数3)

    • 参数1:表明要用哪个类加载器去加载生成的代理类。
    • 参数2:说明要生成的代理类的接口
    • 参数3:实现了InvocationHandle接口的类(本例中是this),这个类只有一个方法需要实现,即invoke();
  • invoke(Object proxy, Method method, Object[] args){}

    • 第一个参数:生成的代理类,目前没发现用处,不管他
    • 第二个参数:执行的方法(利用反射的原理)
    • 第三个参数:执行某方法需要的参数
    • 返回值:执行某方法返回的值

    第二个第三个参数解释执行的方法,意思是:代理类代理的是某个对象,然后增强里面的方法,代理类会将几乎所有方法都增强,除非在这里做判断。

写在最后

Early to bed, early to rise, make a man healthy, wealthy, and wise.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值