代理模式
一.介绍
是一种常见的设计模式,属于结构型模式.
它的核心思想是通过一个 代理对象 来控制对真实对象的访问
从而在不修改目标对象的前提下,实现功能的增强
1.使用场景
-
权限控制
-
日志记录
-
性能检测
-
缓存的处理
2.分类
-
静态代理
-
在编译阶段
-
在写代码期间
-
在程序运行之前,就已经确定了代理类和被代理的类的关系
-
-
动态代理
-
在写代码期间,不确定被代理的类是谁
-
只知道写代理类和他的业务逻辑
-
在运行的时候,动态的创建代理类,灵活性比较高
-

二.静态代理
在编码阶段,已经明确知道哪个类是真实类,哪个类是代理类,二者的关系是硬编码的.
1.案例:程序员接项目
1.1 定义接口:Programmer
//程序员
public interface Programmer {
void code(Integer money);
}
1.2 真实类
public class XiaoMing implements Programmer{
@Override
public void code(Integer money) {
if (money < 7000){
System.out.println("拒绝上班");
return;
}
System.out.println("获得工资:"+money);
System.out.println("开开心心写代码");
}
}
1.3 代理类: OD公司作为代理类,承接业务
//代理类,对外说自己是程序员,其实不会写代码,需要一个真实的程序员来给他写代码
public class OD implements Programmer{
private final Programmer programmer;
public OD(Programmer programmer){
this.programmer = programmer;
}
@Override
public void code(Integer money) {
System.out.println("收到甲方的工资:"+money);
Integer payMoney = 10000;
//保险
Double xian = payMoney * 0.12;
Double jin = payMoney * 0.12;
//公司付出
System.out.printf("公司付出:缴纳五险一金,保险%s元,公积金%s元\n",xian,jin);
System.out.printf("实际发的工资:%s\n",payMoney);
programmer.code(payMoney);
System.out.println("公司赚了:"+(money - xian - jin - payMoney));
}
}
1.4 测试类
public class Hua {
public static void main(String[] args) {
//需要一个野生的程序员,小明
Programmer xiaoming = new XiaoMing();
//招聘小明,开发
Programmer od = new OD(xiaoming);
//支付工资
od.code(40000);
}
}
1.5 特点
-
优点
-
逻辑清晰
-
易于理解和实现
-
-
缺点
-
每个真实类,都需要一个对应的代理类
-
非常不利于维护和扩展
-
不适合大规模的使用
-
三.动态代理
动态代理是在程序运行期间动态的生成代理类,具有更高的灵活性和通用性
常见的实现方式有两种:
| 类型 | 实现机制 | 依赖环境 |
|---|---|---|
| JDK动态代理 | 基于接口实现 | 必须有接口 |
| CGLib动态代理 | 基于继承实现 | 可以没有接口,需要引入cglib库 |
1.JDK动态代理
-
案例:方法执行的时候,统计运行时机,和性能
1.1 自定义: InvocationHandler
public class JDKInvocationHandler implements InvocationHandler {
//真实类
private Object target;
public JDKInvocationHandler(Object object){
this.target = object;
}
//Method 是被执行方法的 方法对象
//args 被执行方法的参数
@Override
public Object invoke(Object proxy,
Method method,
Object[] args) throws Throwable {
//这个方法是用来写业务的---统计性能
//进入方法的时候,记录时间
long start = System.currentTimeMillis();
// result 是方法执行之后的返回值
Object result = method.invoke(target,args);
//执行之后的时间
long time = System.currentTimeMillis() - start;
System.out.printf("[性能统计]方法%s,耗时%s ms \n",method.getName(),time);
return result;
}
}
这里只写了业务逻辑,此时,还不知道被统计性能的类是谁
刚刚的代理类,会在运行时,动态生成
1.2 使用示例
public class TestJdk {
public static void main(String[] args) {
f2();
}
private static void f2() {
//真实类
WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();
JDKInvocationHandler jdkInvocationHandler =
new JDKInvocationHandler(webUserServiceImpl);
WebUserService webUserService =
(WebUserService) Proxy.newProxyInstance(
WebUserServiceImpl.class.getClassLoader(),
new Class[]{WebUserService.class},
jdkInvocationHandler
);
webUserService.findById(100);
}
private static void f1() {
XiaoMing xiaoMing = new XiaoMing();
//jdk 动态代理对象
JDKInvocationHandler jdkInvocationHandler =
new JDKInvocationHandler(xiaoMing);
//创建Programer 代理对象
//创建的代理对象,具备jdkInvocationHandler中的能力
Programmer programmer = (Programmer) Proxy.newProxyInstance(
XiaoMing.class.getClassLoader(),//真实类
new Class[]{Programmer.class},//接口
jdkInvocationHandler//动态代理对象
);
programmer.code(30000);
}
}
2 Cglib动态代理
因为Spring中已经包含了Cglib库,所以不再重新引入
-
案例: 日志打印
2.1 自定义Cglib代理工厂
public class CglibProxyFactory implements MethodInterceptor {
//真实类
private Object target;
public Object getInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy,
Method method,
Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("[cglib]"+method.getName()+"方法被执行,参数:"+ Arrays.toString(args));
//执行方法
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("cglib,返回值:"+result);
return result;
}
}
2.2 测试
public class CglibTest {
public static void main(String[] args) {
//真实类
WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();
//工厂类
CglibProxyFactory factory = new CglibProxyFactory();
//设置真实类
WebUserService webUserService = (WebUserService) factory.getInstance(webUserServiceImpl);
WebUser webUser = webUserService.findById(99);
}
}
四.总结
-
代理模式,代码可以看懂就合格了
-
重点是能把代理模式描述清楚
-
有能力了,可以把代码敲一遍
7750

被折叠的 条评论
为什么被折叠?



