一、核心概念:代理模式就像房屋中介
想象你要租一套房子:
- 你:租客(业务调用者)
- 房东:房主(真实业务对象)
- 中介:代理对象
传统方式(无代理)
租客 → 直接找房东
↓
房东处理所有事情:
1. 带看房
2. 签合同
3. 收租金
4. 处理维修
问题:房东被各种琐事淹没,无法专注核心业务(管理房屋)
二、代理模式解决方案
租客 → 联系中介(代理)
↓
中介处理辅助事务:
1. 带看房
2. 签合同
3. 收租金
4. 处理维修
↓
房东只做核心业务:确认租赁关系
三、Spring AOP 中的两种代理
1. JDK 动态代理:基于接口的代理
场景:房东有明确的"租赁服务"接口
// 租赁服务接口
public interface RentalService {
void signContract();
void collectRent();
}
// 真实房东(实现接口)
public class Landlord implements RentalService {
public void signContract() {
System.out.println("房东签署合同");
}
public void collectRent() {
System.out.println("房东收取租金");
}
}
// 中介(代理)
public class AgencyProxy implements InvocationHandler {
private Object target; // 持有房东引用
public Object createProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
public Object invoke(Object proxy, Method method, Object[] args) {
// 前置增强:带看房
System.out.println("中介带租客看房");
// 调用房东方法
Object result = method.invoke(target, args);
// 后置增强:处理维修
System.out.println("中介安排房屋维修");
return result;
}
}
// 租客使用
public class Renter {
public static void main(String[] args) {
Landlord realLandlord = new Landlord();
RentalService proxy = (RentalService) new AgencyProxy().createProxy(realLandlord);
proxy.signContract();
proxy.collectRent();
}
}
输出结果:
中介带租客看房
房东签署合同
中介安排房屋维修
中介带租客看房
房东收取租金
中介安排房屋维修
2. CGLIB 代理:基于子类的代理
场景:房东没有实现接口
// 房东(无接口)
public class Landlord {
public void signContract() {
System.out.println("房东签署合同");
}
public void collectRent() {
System.out.println("房东收取租金");
}
}
// 中介(代理)
public class AgencyInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
// 前置增强
System.out.println("中介带租客看房");
// 调用房东方法
Object result = proxy.invokeSuper(obj, args);
// 后置增强
System.out.println("中介安排房屋维修");
return result;
}
}
// 租客使用
public class Renter {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Landlord.class);
enhancer.setCallback(new AgencyInterceptor());
Landlord proxy = (Landlord) enhancer.create();
proxy.signContract();
proxy.collectRent();
}
}
输出结果:与JDK代理相同
四、Spring AOP 如何选择代理方式?
实际场景对比:
代理类型 | 比喻场景 | 优势 | 限制 |
---|---|---|---|
JDK动态代理 | 房东有租赁资质证书(接口) | 无需额外依赖 | 只能代理接口方法 |
CGLIB代理 | 房东是个人房东(无证书) | 可代理普通类 | 无法代理final方法 |
五、Spring AOP 代理工作流程
六、为什么需要代理模式?
1. 解决核心问题:关注点分离
关注点 | 房东职责 | 中介职责 |
---|---|---|
核心业务 | 确认租赁关系 | - |
辅助事务 | - | 带看房/签合同/维修 |
客户接触 | - | 直接面对租客 |
2. 实际开发中的对应关系
房屋租赁 | Spring AOP | 技术实现 |
---|---|---|
房东 | 服务类(如UserService) | @Service |
中介 | 代理对象 | Spring容器创建 |
带看房 | 前置通知 | @Before |
签合同 | 核心方法 | 业务逻辑 |
处理维修 | 后置通知 | @After |
租赁接口 | 服务接口 | UserService接口 |
七、实际代码示例
1. 定义切面(中介服务)
@Aspect
@Component
public class AgencyServices {
// 带看房服务(前置通知)
@Before("execution(* com.example.service.*.*(..))")
public void showHouse() {
System.out.println("中介带租客看房");
}
// 处理维修(后置通知)
@After("execution(* com.example.service.*.*(..))")
public void handleMaintenance() {
System.out.println("中介安排房屋维修");
}
}
2. 业务服务(房东)
@RestController
public class RentalController {
@Autowired
private LandlordService landlordService;
@PostMapping("/sign")
public String signContract() {
landlordService.signContract();
return "签约成功";
}
}
3. 客户端调用
@Service
public class LandlordService {
public void signContract() {
System.out.println("房东签署合同");
}
public void collectRent() {
System.out.println("房东收取租金");
}
}
4. 执行结果
访问 POST /sign
输出:
中介带租客看房
房东签署合同
中介安排房屋维修
八、代理模式的优势总结
职责清晰:
- 房东专注核心业务
- 中介处理辅助事务
扩展灵活:
- 新增服务只需添加新切面
- 不影响核心业务逻辑
解耦彻底:
- 房东不知道中介存在
- 中介不知道房东具体实现
保护目标对象:
- 租客不直接接触房东
- 中介控制访问流程
九、Spring AOP 代理的本质
通过代理对象包裹目标对象,在不修改原始代码的前提下,在方法执行前后插入增强逻辑,实现功能扩展。