本文最后更新于 2025年7月26日 中午
代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。
角色
- 抽象主题角色 : 抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类
- 真实主题角色 : 该类也称为被代理类,定义了代理所表示的真实对象,是负责执行系统真正逻辑的业务对象
- 代理主题角色 : 也称为代理类,其内部持有RealSubject的引用,因此完全具备对RealSubject的代理权。客户端调用代理对象的方法,同时也调用被代理对象的方法。
分类
- 静态代理:由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件已经存在
- 动态代理:在程序运行时,运用反射机制动态创建而成,无须手动编写代码
场景
- 保护目标对象
- 增强目标对象
静态代理
静态代理本身就是一种委托调用的实现,定义代理类接收被代理类,对被代理类进行增强。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public interface UserService { void saveUser();
Object findUser(int uid);
}
public class UserServiceImpl implements UserService{ @Override public void saveUser(){ System.out.println("调用DAO保存用户信息"); }
@Override public Object findUser(int uid){ System.out.println("调用DAO查询用户信息"); return "user{name:'codfish'}"; } }
public class UserServiceProxy implements UserServices { private UserService userService ;
public class UserServiceProxy(UserService userService){ this.userService = userService; }
@Override public void saveUser(){ long startTime = System.currentTimeMillis(); userService.saveUser(); long endTime = System.currentTimeMillis(); System.out.println("saveUser方法耗时:" + (endTime-startTime)); }
@Override public Object findUser(int uid){ long startTime = System.currentTimeMillis(); Object rs = userService.findUser(uid); long endTime = System.currentTimeMillis(); System.out.println("findUser 方法耗时:" + (endTime - startTime)); return rs ; } }
public class Test{ public static void main(String[] args){ UserService userService = new UserServiceProxy(new UserServiceImpl()); userService.saveUser(); userService.findUser(); } }
|
动态代理
普通的静态代理,只能在同一接口定义下,完成对被代理类的代理过程。
这时可以使用动态代理,来对在编码时不确定具体接口,类信息的对象进行动态代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public class JDKProxy implements InvocationHandler { private Object target ; Object proxy = Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); @Override public Object invoke(Object proxy , Method method, Object[] args) throws Throwable{ long startTime = System.currentTimeMillis(); Object rs = method.invoke(target , args); long endTime = System.currentTimeMillis(); System.out.println("JDK Proxy耗时:" + (endTime-startTime)); return rs ; } }
public class Test{ public static void main(String[] args){ JDKProxy jdkProxy = new JDKProxy(); UserService userService = (UserService)jdkProxy.bind(new UserServiceImpl()); userService.saveUser(); userService.findUser(); } }
|
这样就可以在不修改原有对象的基础上,完成对原对象方法的调用
JDK实现的动态代理的缺点是 被代理类必须实现了接口。
而另一种方式是 通过使用CGLib 完成动态代理过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class UserService { public void saveUser() { System.out.println("保存用户"); }
public void findUser() { System.out.println("查找用户"); } }
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object bind(Object target) { this.target = target;
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); }
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { long startTime = System.currentTimeMillis(); Object rs = proxy.invoke(target, args); long endTime = System.currentTimeMillis(); System.out.println("CGLIB Proxy耗时:" + (endTime - startTime)); return rs; } }
public class Test { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); UserService userService = (UserService) cglibProxy.bind(new UserService()); userService.saveUser(); userService.findUser(); } }
|
CGLIB 是通过创建被继承类的子类来完成代理过程的,所以在使用CGLiB 进行动态代理创建的时候,无法为被final 修饰的类创建动态代理。
总结
代理模式通过引入一个代理对象,在不修改目标对象的前提下,控制对目标对象的访问或增强其功能。它将请求的发起与实际执行进行解耦,常用于权限控制、延迟加载、远程调用与功能扩展等场景。代理模式包括静态代理和动态代理两种形式,静态代理在编译期生成代码,适合结构清晰的场景;动态代理则在运行时生成代理类,更加灵活,常用于 AOP 和框架设计中,是实现开闭原则和职责分离的重要手段。