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
重构获取代理对象方法: 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动态代理机制][CGLIB]
还没有评论,来说两句吧...