1、代理模式

二、结构型模式

    1、代理模式

        (1)、概述

            代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:在不改动原有代码的前提下,在已有代码基础上添加新的功能,从而增强原功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

        (2)、分类

            ①、静态代理(静态定义代理类):静态代理实现起来比较简单,需要提前定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。但静态代理需要去实现每一个被代理的类以及方法,如果被代理的方法比较多,会比较繁琐。

            ②、动态代理(动态生成代理类):

                a、JDK动态代理:需要被代理类一定要实现某个接口,而代理类只需要实现InvocationHandler接口。代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。只能对实现了接口的类生成代理,而不能针对类,对于没有实现接口的类无法实现JDK动态代理。Spring会使用JDK Proxy去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理,因为Proxy.newProxyInstance()方法会返回的是一个指定接口的代理类实例,需要用接口接收。

                b、cglib动态代理:提供的动态代理不需要类实现了某个接口,是针对类实现代理。cglib采用继承的方式实现动态代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

        (3)、静态代理的代码实现

            ①、定义Automobile接口

public interface Automobile {

    String doSomething(String series);

}

            ②、被代理类实现Automobile接口

public class Benz implements Automobile {

    @Override

    public String doSomething(String series) {

        return String.format("德国奔驰:%s",series);

    }

}

            ③、代理类实现Automobile接口

public class BeijingBenz implements Automobile {

    private Benz benz;

    public BeijingBenz(Benz benz){

        this.benz = benz; 

    }

    @Override

    public String doSomething(String series) {

        System.out.println("我是北京奔驰,我代理德国奔驰");

        String msg =  benz.doSomething(series);

        System.out.println(msg);

        return msg;

    }

}

            ④、实现静态代理

public class Main {

    public static void main(String[] args) {

        Benz benz = new Benz();

        BeijingBenz beijingBenz = new BeijingBenz(benz);

        beijingBenz.doSomething("S600");

    }

}

            ⑤、实际应用

                TokenCallable通过代理Callable实现token的传递,以及日志打印的一些信息。

public class TokenCallable<V> implements Callable<V> {

    private final String accessToken;

    /**

     * 被代理的Callable

     */

    private final Callable<V> delegate;

    private final String taskName;

    public TokenCallable(Callable<V> delegate, String accessToken,String taskName) {

        this.delegate = CallableWrapper.of(delegate);

        this.accessToken = accessToken;

        this.taskName = taskName;

    }

    @Override

    public V call() throws Exception {

       long start = System.currentTimeMillis();

        LogUtil.debug("currentThreadId = " + Thread.currentThread().getId() + ",accessToken=" + accessToken);

        //给当前线程设置token

        AccessTokenUtil.setAccessToken(accessToken);

        V call = delegate.call();

        LogUtil.info("taskName =" + taskName + ",taskTime = " + (System.currentTimeMillis() - start) + " ms");

        return call;

    }

}

        (4)、JDK动态代理的代码实现

            ①、定义Automobile接口

public interface Automobile {

    String doSomething(String series);

}

            ②、被代理类实现Automobile接口

public class BMW implements Automobile {

    @Override

    public String doSomething(String series) {

        return String.format("德国宝马 %s", series);

    }

}

            ③、代理类实现InvocationHandler接口

public class HuachenBMW implements InvocationHandler {

    public Automobile target;

    public HuachenBMW(Automobile target) {

        this.target = target;

    }

    @Override

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

        System.out.println("来中国混,根据指示找代理");

        Object ret = method.invoke(target, args);

        System.out.println("代理车系是:" + ret);

        return ret;

    }

}

            ④、实现JDK动态代理

public class Main {

    public static void main(String[] args) {

        BMW BMW = new BMW();

        HuachenBMW huachenBMW = new HuachenBMW(BMW);

        //通过Proxy.newProxyInstance()方法返回一个指定接口的代理类实例

        Automobile automobile = (Automobile)Proxy.newProxyInstance(BMW.getClass().getClassLoader(),

                BMW.getClass().getInterfaces(),

                huachenBMW);

        String series = automobile.doSomething("X6");

        System.out.println("抢到一辆:"+ series);

    }

}

        (5)、cglib动态代理的代码实现

            ①、引入cglib的jar包

<dependency>

    <groupId>cglib</groupId>

    <artifactId>cglib</artifactId>

    <version>3.2.10</version>

</dependency>

            ②、定义被代理类

public class Audi {

    public String doSomething(String series){

        System.out.println("原产于德国的奥迪汽车");

        return String.format("德国奥迪,车系是:%s", series);

    }

}

            ③、代理类实现MethodInterceptor接口

public class FirstAudi implements MethodInterceptor {

    @Override

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("代理德国奥迪汽车");

        Object series =  methodProxy.invokeSuper(o, objects);

        System.out.println(series);

        return series;

    }

}

            ④、实现cglib动态代理

public class Main {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Audi.class);

        enhancer.setCallback(new  FirstAudi());

        Audi audi = (Audi) enhancer.create();

        audi.doSomething("A8");

    }

}

        注:JDK内置动态代码采用Java反射机制实现,cglib库实现的动态代理,采用的是ASM直接操作字节码方式实现。由于反射操作的效率要低于直接操作字节码的效率,所以,cglib实现动态代理效率上比JDK内置的动态代理要好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值