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

 

一、前言

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

二、案例

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

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

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、解析

原文地址:https://www.cnblogs.com/shyroke/p/11994852.html