1097 字
约 3 分钟
1
代理设计模式(Proxy Pattern)
代理设计模式(Proxy Pattern)
1. 什么是代理模式?
代理模式:不直接访问目标对象,而是通过代理对象间接访问目标对象,由代理对象控制目标方法的执行逻辑。
简单理解:
原本应该由目标对象完成的事情,交给代理对象处理,代理可以在调用目标方法前后增加额外逻辑。
2. 现实例子
张三想买房,但是:
- 不懂房产市场
- 不知道如何找房
- 不懂交易流程
于是找到房产中介。
流程:
张三
|
| 委托买房
↓
中介(代理)
|
| 看房
| 谈价格
| 办手续
↓
完成购房
张三只需要和中介沟通,不需要关心背后的找房、谈判、手续流程。
这就是代理:
隐藏复杂流程,让调用方只关注自己的目标。
3. Java 中的代理
例如 Mybatis:
我们平时写:
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.findUser();
看起来只是调用 Mapper 方法。
但是实际上 Mybatis 在背后完成:
Mapper代理对象
|
↓
解析方法
|
↓
生成SQL
|
↓
获取数据库连接
|
↓
执行SQL
|
↓
封装返回结果
开发者不需要关注 JDBC 的细节。
4. CGLIB 动态代理示例
引入依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
代码:
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
public class CGLibProxyDemo {
public static void main(String[] args) {
HelloTarget target = new HelloTarget();
Enhancer enhancer = new Enhancer();
// 代理目标类
enhancer.setSuperclass(HelloTarget.class);
// 设置代理逻辑
enhancer.setCallback(new MethodInterceptor() {
@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("方法执行后");
return result;
}
});
// 创建代理对象
HelloTarget proxy =
(HelloTarget) enhancer.create();
// 调用代理方法
proxy.sayHello();
}
}
class HelloTarget {
public void sayHello() {
System.out.println("Hello World");
}
}
执行结果:
方法执行前
Hello World
方法执行后
5. 两个重要方法区别
proxy.invokeSuper()
调用:
代理对象
|
↓
目标对象方法
也就是:
执行真正的目标方法。
例如:
proxy.invokeSuper(obj,args);
相当于:
target.sayHello();
proxy.invoke()
调用:
代理对象
|
↓
代理方法
|
↓
再次进入 intercept()
容易产生:
intercept()
|
↓
invoke()
|
↓
intercept()
|
↓
invoke()
|
↓
无限循环
最终导致:
StackOverflowError
所以 CGLIB 中调用目标方法通常使用:
proxy.invokeSuper()
6. 代理可以做什么?
代理最大的作用:
① 方法增强
在目标方法前后增加逻辑。
例如:
开始事务
执行方法
提交事务
② 异常处理
例如:
调用方法
如果异常:
记录日志
发送报警
回滚事务
③ 修改返回结果
例如:
目标方法返回数据
代理进行包装
返回新的数据
7. 常见应用场景
AOP
Spring AOP 本质就是代理。
例如:
@Transactional
public void saveUser(){
}
执行:
代理对象
开启事务
调用saveUser()
提交事务
开发者不用手动写事务代码。
Mybatis
Mapper 接口本身没有实现类。
例如:
userMapper.selectById(1);
实际调用:
Mapper代理对象
↓
SqlSession
↓
执行SQL
↓
返回结果
RPC
RPC 调用:
userService.getUser();
看起来像调用本地方法。
实际:
客户端代理
↓
封装请求
↓
序列化
↓
网络传输
↓
服务发现
↓
负载均衡
↓
调用远程服务
↓
返回结果
这些过程用户完全不知道。
8. 总结
代理模式核心:
① 屏蔽复杂实现
让调用者只关注业务:
调用方法
而不用关心:
连接
解析
网络
事务
日志
权限
② 增强目标方法
代理可以在目标方法:
- 执行前
- 执行后
- 出异常时
- 返回结果时
增加额外逻辑。
一句话总结:
代理模式就是通过代理对象控制目标对象的访问,并在不修改目标代码的情况下增强目标方法。
代理设计模式(Proxy Pattern)
http://www.clxhxhhr.top/posts/376/ 评论
0 条
还没有评论,先写一条吧。