一、代理模式基础概念
1.1 什么是代理模式
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不修改目标对象代码的情况下增强其功能。
1.2 代理模式的核心组成
-
抽象主题(Subject): 定义代理和真实主题的公共接口
-
真实主题(RealSubject): 实际业务逻辑的实现类
-
代理类(Proxy): 持有真实主题的引用,提供与真实主题相同的接口
1.3 代理模式的应用场景
-
远程代理(Remote Proxy):为远程对象提供本地代理
-
虚拟代理(Virtual Proxy):延迟创建开销大的对象
-
保护代理(Protection Proxy):控制对原始对象的访问权限
-
智能引用(Smart Reference):在访问对象时执行额外操作
二、静态代理详解
2.1 静态代理实现原理
静态代理在编译期就已经确定代理关系,代理类和目标类实现相同的接口,代理类通过组合方式持有目标对象引用。
2.2 完整静态代理案例
接口定义
public interface BuyClothes {
void clothes(String size);
}
目标类实现
public class ClothesFactory implements BuyClothes {
public void clothes(String size) {
System.out.println("为您定制了一款大小为" + size + "的衣服");
}
}
代理类实现
public class ClothesProxy implements BuyClothes {
private ClothesFactory clothesFactory;
public ClothesProxy() {
this.clothesFactory = new ClothesFactory();
}
@Override
public void clothes(String size) {
preService();
clothesFactory.clothes(size);
postService();
}
private void preService() {
System.out.println("[静态代理]为您进行市场调研");
}
private void postService() {
System.out.println("[静态代理]为您提供售后服务");
}
}
客户端调用
public class StaticProxyTest {
public static void main(String[] args) {
BuyClothes proxy = new ClothesProxy();
proxy.clothes("XL");
}
}
2.3 静态代理的优缺点
优点:
-
结构清晰,易于理解
-
不改变目标对象的情况下扩展功能
缺点:
-
代理类和目标类必须实现相同接口
-
每个目标类都需要一个代理类,导致类数量膨胀
-
接口变更时,代理类和目标类都需要修改
三、动态代理深入解析
3.1 JDK动态代理原理
JDK动态代理利用Java反射机制,在运行时动态生成代理类。核心类:
-
java.lang.reflect.Proxy: 创建代理实例 -
java.lang.reflect.InvocationHandler: 调用处理器接口
3.2 完整JDK动态代理案例
新增鞋子接口
public interface BuyShoes {
void shoes(String size);
}
鞋子目标类
public class ShoesFactory implements BuyShoes {
@Override
public void shoes(String size) {
System.out.println("为您定制了一款大小为" + size + "的鞋子");
}
}
动态代理处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
preProcess();
Object result = method.invoke(target, args);
postProcess();
return result;
}
private void preProcess() {
System.out.println("[动态代理]执行前置处理");
}
private void postProcess() {
System.out.println("[动态代理]执行后置处理");
}
}
客户端调用
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
// 代理衣服购买
BuyClothes clothes = new ClothesFactory();
DynamicProxyHandler clothesHandler = new DynamicProxyHandler(clothes);
BuyClothes clothesProxy = (BuyClothes) Proxy.newProxyInstance(
clothes.getClass().getClassLoader(),
clothes.getClass().getInterfaces(),
clothesHandler);
clothesProxy.clothes("L");
// 代理鞋子购买
BuyShoes shoes = new ShoesFactory();
DynamicProxyHandler shoesHandler = new DynamicProxyHandler(shoes);
BuyShoes shoesProxy = (BuyShoes) Proxy.newProxyInstance(
shoes.getClass().getClassLoader(),
shoes.getClass().getInterfaces(),
shoesHandler);
shoesProxy.shoes("42");
}
}
3.3 JDK动态代理的优缺点
优点:
-
一个代理类可以代理多个接口
-
减少代码冗余,提高可维护性
-
符合开闭原则,系统扩展性好
限制:
-
只能代理接口,不能代理类
-
反射调用有一定性能开销
四、CGLIB动态代理
4.1 CGLIB原理
CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过继承目标类并在运行时生成子类来实现代理。
4.2 CGLIB代理案例
目标类(不需要实现接口)
public class ProductService {
public void createProduct(String name) {
System.out.println("创建产品:" + name);
}
}
CGLIB代理工厂
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxyFactory implements MethodInterceptor {
public Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
preProcess();
Object result = proxy.invokeSuper(obj, args);
postProcess();
return result;
}
private void preProcess() {
System.out.println("[CGLIB代理]执行前置处理");
}
private void postProcess() {
System.out.println("[CGLIB代理]执行后置处理");
}
}
客户端调用
public class CglibTest {
public static void main(String[] args) {
CglibProxyFactory factory = new CglibProxyFactory();
ProductService proxy = (ProductService) factory.getProxy(ProductService.class);
proxy.createProduct("智能手机");
}
}
4.3 CGLIB特点
优势:
-
可以代理普通类,不要求实现接口
-
生成的代理类是目标类的子类
-
方法调用比JDK动态代理更快
限制:
-
不能代理final类或final方法
-
需要引入额外依赖
五、三种代理方式对比
|
特性 |
静态代理 |
JDK动态代理 |
CGLIB代理 |
|---|---|---|---|
|
实现方式 |
手动编码 |
反射机制 |
字节码生成 |
|
代理目标 |
接口 |
接口 |
类 |
|
编译期生成 |
是 |
否 |
否 |
|
性能 |
高 |
中 |
高 |
|
依赖 |
无 |
JDK自带 |
需要引入CGLIB |
|
适用场景 |
简单固定代理 |
多接口代理 |
无接口类代理 |
六、Spring中的代理选择
Spring框架自动根据目标对象选择代理方式:
-
如果目标对象实现了接口 → 使用JDK动态代理
-
如果目标对象没有实现接口 → 使用CGLIB代理
-
可以通过配置强制使用CGLIB代理
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AppConfig {
// 配置类
}
七、最佳实践建议
-
优先使用JDK动态代理:符合面向接口编程原则
-
必要时使用CGLIB:当需要代理类而非接口时
-
避免滥用代理:明确代理的目的,不要为了使用模式而使用
-
性能考虑:在高性能场景下评估代理开销
-
结合AOP使用:Spring AOP等框架已经提供了良好的代理实现
通过本文的详细讲解和完整代码示例,您应该已经掌握了Java中各种代理模式的实现原理和使用场景。在实际开发中,可以根据具体需求选择合适的代理方式,灵活运用代理模式来增强系统功能。

368

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



