java代理模式学习,静态代理,JDK动态代理,CGLIB动态代理

                java代理模式学习,静态代理,JDK动态代理,CGLIB动态代理

 

一、理解代理

1、代理,Proxy 。意思是:本来该你做的事儿,别人代替你去做。 比如说:即将十一到来,你要抢回家/旅游的车票,可是你不能时时刻刻在电脑前一遍又一遍的刷着12306。 这时交给了 飞猪 等(此处省去若干个抢票软件!)软件帮助你抢。 飞猪就是你 抢票 这项工作的代理 。

2、代理作用: 日志记录,性能分析,解耦合。。。 自己百度去。

二、静态代理 --- 代码来抢票

1、 定义一个抢票接口 Tickets

/**
* description: 抢票接口 --- 需要抢票需实现该接口
* @version v1.0
* @author w
* @date 2018年9月3日下午9:54:28
*/
public interface Tickets {
    void buyTickets();
}

2、定义一个User类 实现抢票接口,执行抢票操作

/**
* description: 定义一个User类 实现抢票接口,执行抢票操作
* @version v1.0
* @author w
* @date 2018年9月3日下午9:52:38
*/
public class User implements Tickets{
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void buyTickets() {
        System.out.println(name + " 开始抢票啦~ ");
    }
}

3、定义一个FliggyProxy类,实现抢票接口 --- 飞猪来帮你抢票啦

/**
* description: 飞猪 实现抢票接口 --- 飞猪来帮你抢票啦
* @version v1.0
* @author w
* @date 2018年9月3日下午9:58:44
*/
public class FliggyProxy implements Tickets {

    private User user ;

    public FliggyProxy(User user) {
        this.user = user;
    }

    @Override
    public void buyTickets() {
        System.out.println("充钱,享受1000M专线抢票 ");
        user.buyTickets();
        System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
    }
}

4、定义一个 StaticProxyTest类,执行相关的测试操作

/**
* description: 静态代理 test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:01:26
*/
public class StaticProxyTest {

    @Test
    public void testOne(){
        // 创建一个用户,小明 --- 一遍又一遍的刷着12306
        User user = new User("小明");
        user.buyTickets();
    }

    @Test
    public void testTwo(){
        // 创建一个需要抢票的用户 --- 万能小明
        User user = new User("万能小明");
        // 小明开启飞猪
        FliggyProxy fliggy = new FliggyProxy(user);
        // fliggy 开始抢票啦
        fliggy.buyTickets();
    }
}

5、运行结果:

testOne:小明 开始抢票啦~
testTwo:
充钱,享受1000M专线抢票
万能小明 开始抢票啦~
抢票成功. 广告:没有什么是充钱解决不的问题.

6、根据代码运行结果可以小明抢票的操作,交给飞猪后,很快就抢到了。 但是 飞猪的功能太单一,只能帮忙抢票。比如下次要抢月饼呢,再下次要抢手机呢? 要实现这些功能,我们就要写n多个的 xxProxy。 作为程序员,总想着一劳永逸,能否只写一个呢? 答案是有的,继续往下。

三、JDK动态代理

1、定义一个 FliggyDynamic 类,实现 java.lang.reflect.InvocationHandler 接口 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* description: JDK动态代理。 飞猪动态帮助无数人开启抢票模式
* @version v1.0
* @author w
* @date 2018年9月3日下午10:06:21
*/
public class FliggyDynamic implements InvocationHandler {

    /**
    * 需要抢票的用户 --- 目标代理对象
    */
    private Object target ;

    /**
    * 构造方法,初始化目标代理对象
    */
    public FliggyDynamic(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("充钱,享受1000M专线抢票 ");
        Object result = method.invoke(target, args);
        System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
        return result;
    }
}


 

2、定义一个 DynamicTest类,执行相关的测试操作

/**
* description: JDK 动态代理Test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:09:02
*/
public class DynamicTest {
    @Test
    public void test(){
        User user = new User("万年小明");
        FliggyDynamic dynamic = new FliggyDynamic(user);
        Tickets proxy = (Tickets)Proxy.newProxyInstance(user.getClass().getClassLoader(),
        user.getClass().getInterfaces(), dynamic);
        proxy.buyTickets();
    }
}

3、运行结果:

充钱,享受1000M专线抢票
万年小明 开始抢票啦~
抢票成功. 广告:没有什么是充钱解决不的问题.

4、定义 FliggyDynamicRefactor<T>类,实现 InvocationHandler 接口,增加泛型。 (可选)

            重构获取代理对象方法: Proxy.newProxyInstance .... 避免每次都进行强制类型转换。

/**
* description: JDK动态代理 。 重构 Proxy.newProxyInstance , 避免每次都进行强制类型转换。
* @version v1.0
* @author w
* @date 2018年9月3日下午10:52:07
*/
public class FliggyDynamicRefactor<T> implements InvocationHandler{

    /**
    * 目标代理对象 target
    */
    private T target ;

    public FliggyDynamicRefactor(T target) {
        this.target = target;
    }

    /**
    * description: 获取代理对象
    * @return
    * T
    * @version v1.0
    * @author w
    * @date 2018年9月3日 下午10:55:59
    */
    @SuppressWarnings("unchecked")
    public T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                          target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("充钱,享受1000M专线抢票 ");
        Object result = method.invoke(target, args);
        System.out.println("抢票成功. 广告:没有什么是充钱解决不的问题.");
        return result;
    }
}

5、定义 DynamicRefactorTest 类,对重构后的代码进行测试 (可选)

/**
* description: JDK 动态代理 重构后的 FliggyDynamicRefactor Test
* @version v1.0
* @author w
* @date 2018年9月3日下午10:09:02
*/
public class DynamicRefactorTest {

    @Test
    public void test(){
        FliggyDynamicRefactor<Tickets> refactor = new FliggyDynamicRefactor<Tickets>(new User("李雷"));
        refactor.getProxy().buyTickets();
    }
}

6、运行结果:

充钱,享受1000M专线抢票
李雷 开始抢票啦~
抢票成功. 广告:没有什么是充钱解决不的问题.

7、使用JDK提供的动态代理,可以解决静态代理中要写 n多个 xxProxy类的问题。但是可以发现,JDK动态代理只能针对接口的代理。 若一个类,没有实现任何接口,那么JDK的动态代理也就无用武之地了。 有解决办法吗?有,继续看 CGLIB的动态代理 ---- 针对类的代理。

四、CGLIB动态代理

1、 依赖jar包: cglib-3.2.6.jar

2、定义一个 Car 类,不实现任何 接口的普普通通类

/**
* description: 定义一个普通的 Car类
* @version v1.0
* @author w
* @date 2018年9月3日下午11:27:09
*/
public class Car {
    public void runing(){
        System.out.println("老司机开车啦~ ");
    }
}

3、定义一个 CglibProxy类,实现 net.sf.cglib.proxy.MethodInterceptor 接口


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* description: 使用 CGLIB 实现动态代理
* @version v1.0
* @author w
* @date 2018年9月3日下午11:12:55
*/
public class CglibProxy implements MethodInterceptor{
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clzz){
        return (T) Enhancer.create(clzz, this);
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前方注意~老司机来了,请速让道。。 ");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("老司机已通过前方 over ..");
        return result;
    }
}

4、定义 CglibProxyTest类,针对CglibProxy的测试

/**
* description: 针对 CglibProxy 的测试
* @version v1.0
* @author w
* @date 2018年9月3日下午11:46:34
*/
public class CglibProxyTest {
    @Test
    public void test(){
        CglibProxy proxy = new CglibProxy();
        Car car = proxy.getProxy(Car.class);
        car.runing();
    }
}

5、运行结果:

前方注意~老司机来了,请速让道。。
老司机开车啦~
老司机已通过前方 over ..

6、可以看到,使用 CGLIB解决了JDK的动态代理只能针对接口代理的问题。 普通的java类都可以进行代理。

五、总结

1、代理模式,实现代码功能增强,且不影响原代码,解耦合。

2、静态代理,针对每一个代理对象都需要都需要一个代理类。

3、JDK动态代理,只能针对接口代理,若目标代理类未实现接口,则无法代理。

4、CGLIB动态代理,可以对普通类进行代理,但目标代理类需提供无参构造方法。

参考资料: http://www.importnew.com/26116.html

         深入理解CGLIB动态代理机制

猜你喜欢

转载自blog.csdn.net/HaHa_Sir/article/details/82386679
今日推荐