一、核心概念:代理模式就像房屋中介
想象你要租一套房子:
- 你:租客(业务调用者)
- 房东:房主(真实业务对象)
- 中介:代理对象
传统方式(无代理)
租客 → 直接找房东↓
房东处理所有事情: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 {@Autowiredprivate 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 代理的本质
通过代理对象包裹目标对象,在不修改原始代码的前提下,在方法执行前后插入增强逻辑,实现功能扩展。