前言:
今天是设计模式我想说的最后模式————代理模式
,代理模式
我认为是最重要的模式了,常用于开源框架底层封装,如Spring,Mybatis,HDFS,RPC,xxl-job 等;主要是aop的思想,业务中常用日志切面,接口访问量,并发量控制,简单的说是拦截相关请求做自己想做的事
等,今天简单写个例子,并分享一下相关源码
。
今日主题
代理模式:概述:为其他对象提供一种代理可以控制这个对象的访问
场景:
假设某些操作处理,需要其他事物执行,并在执行时动态的去扩展,可以采用。
在这里,我简单写了个demo,模拟某些操作需要代理,其中计算操作代理,计算操作前后需要处理一些事情。
代码如下
'设计模式'代码
package com.huey.designpattern.dynamicproxy;
/**
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ 神兽保佑
* ┃ ┃ 代码无BUG!
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
* @author huey
* @Description : 代理操作
* @Date Created in 2018/10/21 20:23
*/
public interface ProxyOperation<T> {
/**
* @author huey
* @Description : 其他对象初始化
* @Date Created in 2018/10/21 20:27
*/
void init();
/**
* @author huey
* @Description : 钩子 是否计算了
* @Date Created in 2018/10/21 20:25
*/
boolean isCalc(boolean flag);
/**
* @author huey
* @Description : 计算后,其他对象后置处理
* @Date Created in 2018/10/21 20:27
*/
void postProcessor();
}
package com.huey.designpattern.dynamicproxy;
/**
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ 神兽保佑
* ┃ ┃ 代码无BUG!
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
* @author huey
* @Description : 业务:计算
* 实际目标对象接口
* @Date Created in 2018/10/21 20:18
*/
public interface ProxyCalcOperation extends ProxyOperation {
void calc();
}
package com.huey.designpattern.dynamicproxy;
import lombok.extern.slf4j.Slf4j;
/**
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ 神兽保佑
* ┃ ┃ 代码无BUG!
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*
* @author huey
* @Description : 业务默认计算操作目标对象
* @Date Created in 2018/10/21 20:21
*/
@Slf4j
public class ProxyCalcOperationDefault implements ProxyCalcOperation {
@Override
public void calc() {
log.info("ProxyCalcOperationDefault --> {}","calc");
}
/**
* @author huey
* @Description : 其他对象初始化
* @Date Created in 2018/10/21 20:27
*/
@Override
public void init() {
log.info("ProxyCalcOperationDefault --> {}","init");
}
/**
* @param flag
* @author huey
* @Description : 钩子 是否计算了
* @Date Created in 2018/10/21 20:25
*/
@Override
public boolean isCalc(boolean flag) {
return false;
}
/**
* @author huey
* @Description : 计算后,其他对象后置处理
* @Date Created in 2018/10/21 20:27
*/
@Override
public void postProcessor() {
log.info("ProxyCalcOperationDefault --> {}","postProcessor");
}
}
package com.huey.designpattern.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ ┳┛ ┗┳ ┃
* ┃ ┃
* ┃ ┻ ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ 神兽保佑
* ┃ ┃ 代码无BUG!
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*
* @author huey
* @Description : 代理简单工具类
* @Date Created in 2018/10/21 20:33
*/
public class ProxyOperationUtil {
public static ProxyCalcOperation getProxy(ProxyOperation proxyOperation) {
ClassLoader loader = proxyOperation.getClass().getClassLoader();
Class<?>[] interfaces = proxyOperation.getClass().getInterfaces();
//代理类执行的代码,lamda,联想aop
InvocationHandler h = (proxy, method, args) -> {
//前置扩展,非业务代码,模拟其他方法栈调用
proxyOperation.init();
//目标方法
Object result = method.invoke(proxyOperation, args);
//后置扩展,非业务代码,模拟其他方法栈调用
proxyOperation.postProcessor();
return result;
};
ProxyCalcOperation newProxyInstance = (ProxyCalcOperation) Proxy.newProxyInstance(loader, interfaces, h);
return newProxyInstance;
}
}
package com.huey.designpattern.dynamicproxy;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
@Slf4j
public class ProxyOperationTest {
/**
* @author huey
* @Description : 普通
* @Date Created in 2018/10/21 20:52
*/
@Test
public void test1() {
ProxyCalcOperation proxyCalcOperation = new ProxyCalcOperationDefault();
proxyCalcOperation.calc();
}
/**
* @author huey
* @Description : 代理
* @Date Created in 2018/10/21 20:52
*/
@Test
public void test2() {
ProxyCalcOperation proxyCalcOperation = new ProxyCalcOperationDefault();
// 从源码中得知,设置这个值,可以把生成的代理类,输出出来。
ProxyCalcOperation proxy = ProxyOperationUtil.getProxy(proxyCalcOperation);
proxy.calc();
}
/**
* @author huey
* @Description : 生成后 反编译下 查看
* @Date Created in 2018/10/21 22:13
*/
@Test
public void test3() {
//生成的jdk代理类
byte[] bytes = ProxyGenerator.generateProxyClass("$ProxyTl", new Class[]{ProxyCalcOperation.class});
try {
FileOutputStream fileOutputStream = new FileOutputStream("E:\\company\\$ProxyTl.class");
fileOutputStream.write(bytes);
fileOutputStream.flush();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
联想
spring
中的代理模式是什么样的呢?简单列出了4个图,jdk和cglib
两种方式,默认jdk,UT3
中的代理类反编译后可看默认继承Proxy实现目标接口,为啥jdk代理必须是接口形式呢,其实很简单,因为java是单继承。如果哪天再总结spring的小编再跟踪下
。
is_cglib_default.png
jdk代理源码配图
1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png总结
设计模式【六大原则和23种模式】是个学不完的东西,还是要看自己想到哪种程度,读源码,了解框架,非常的
敏感,过瘾
。
最后,谢谢读者们的欣赏,也希望指出其中的不足,小编还会继续边学习边总结
。
谢谢HeadFirst 作者
。设计模式的学习层面结束了!
代码请参考码云:https://gitee.com/tjhuey/CodingGroup
设计模式相关概念请参考:http://naotu.baidu.com/file/5811bf42020e6a2d877b992cfca90d26
进度
- [x]
策略模式
,<span style="color: #43A047; ">已完成</span> - [x]
观察者模式
,<span style="color: #43A047; ">已完成</span>; - [x]
装饰者模式
,<span style="color: #43A047; ">已完成</span>; - [x]
工厂方法模式
,<span style="color: #43A047; ">已完成</span>; - [x]
抽象工厂模式
,<span style="color: #43A047; ">已完成</span>; - [x]
单例模式
,<span style="color: #43A047; ">已完成</span>; - [x]
命令模式
,<span style="color: #43A047; ">已完成</span>; - [x]
适配模式
,<span style="color: #43A047; ">已完成</span>; - [x]
外观模式
,<span style="color: #43A047; ">已完成</span>; - [x]
模板模式
,<span style="color: #43A047; ">已完成</span>; - [x]
状态模式
,<span style="color: #43A047; ">已完成</span>; - [x]
代理模式
,<span style="color: #43A047; ">已完成</span>;
网友评论