(一)设计模式之代理模式

 

 

 

 

一、前言

   AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

 

 

二、案例

以用户去飞猪上买票为例,很明显飞猪平台便是一个代理,飞猪平台在替用户购票的基础上,还增加了额外的功能,比如购票前要校验身份证,购票后需要提供凭证给用户。

 

1、定义购票行为接口,包括获取身份证号、姓名、余额

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface TicketBuy {
 
    /**
     * 买票
     */
    void buy();
 
    /**
     * 获取身份证号
     * @return
     */
    String getId();
 
    /**
     * 获取姓名
     * @return
     */
    String getName();
 
    /**
     * 获取余额
     * @return
     */
    Double getMoney();
}

  

2、定义用户类,即被代理类

复制代码
public class Person implements TicketBuy {

    private String id;

    private String name;

    private Double money;

    @Override
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public void buy() {
        this.money --;
        System.out.println("用户:"+this.getName()+"买一张票,余额还剩:"+money);
    }
}
复制代码

3、定义飞猪平台类,即代理类

复制代码
public class FlyPig implements InvocationHandler {

    private Person target;

    /**
     * 获取被代理人资料
     * @param target
     * @return
     */
    public Object getInstance(Person target){
        this.target = target;
        Class clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("飞猪平台校验身份证+姓名:"+this.target.getId()+"+"+this.target.getName());

        this.target.buy();

        System.out.println("打印凭证!");

        return null;
    }
}
复制代码

4、测试类:

复制代码
public class Test {

    public static void main(String[] args) {
        Person person1 = new Person();
        person1.setName("张三");
        person1.setId("35052511111111111");
        person1.setMoney(100.00);
        TicketBuy proxy = (TicketBuy)(new FlyPig().getInstance(person1));
        proxy.buy();
    }

}
复制代码

结果

 

5、解析

 

posted @   shyroke、  阅读(265)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2017-12-06 (八)Activiti之流程变量和局部流程变量
2017-12-06 (七)Activiti之历史活动查询和历史任务查询和流程状态查询
2017-12-06 (六)Activiti之实现学生请假流程
2017-12-06 (五)Activiti之查看最新版本的流程定义
2017-12-06 (五)Activiti之获取流程定义图片和流程定义删除
2017-12-06 (四)Activiti之流程定义部署之ZIP方式和流程定义查询
作者:shyroke 博客地址:http://www.cnblogs.com/shyroke/ 转载注明来源~
点击右上角即可分享
微信分享提示