Java 反射机制之代理模式
简介
代理模式--使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能
- 主要作用是扩展目标对象的功能,比如在目标对象的某个方法执行前后可以增加一些自定义的操作,日志记录便是如此
静态代理
静态代理实现步骤
- 定义一个接口及其实现类
- 创建一个代理类并实现这个接口
- 将目标对象作为成员变量注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后扩展目标对象的功能
定义一个接口及其实现类
public interface SendEmailService {
String send(String content);
}
public class SendEmailServiceImpl implements SendEmailService{
@Override
public String send(String content) {
System.out.println("发送邮件内容为 "+content);
return content;
}
}
创建一个代理类并实现这个接口
public class SendEmailProxy implements SendEmailService{
private final SendEmailService sendEmailService;
public SendEmailProxy(SendEmailService sendEmailService) {
this.sendEmailService = sendEmailService;
}
@Override
public String send(String content) {
//调用方法之前,可以添加自己的操作
System.out.println("开始发送邮件");
sendEmailService.send(content);
//调用方法之后,可以添加自己的操作
System.out.println("结束发送邮件");
return content;
}
}
测试
SendEmailServiceImpl emailService = new SendEmailServiceImpl();
SendEmailProxy proxy = new SendEmailProxy(emailService);
proxy.send("静态代理实现");
输出结果为
开始发送邮件
发送邮件内容为 静态代理实现
结束发送邮件
动态代理
动态代理相比于静态代理更加灵活。它不需要针对每个目标类都单独创建一个代理类,并且也不需要必须实现接口,可以直接代理实现类( 如 CGLIB 动态代理机制)
从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的
JDK 动态代理机制
JDK 动态代理机制是基于接口的形式代理的
Proxy
类中newProxyInstance()
方法主要用来生成一个代理对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{
......
}
newProxyInstance()
方法参数说明
-
loader:类加载器,用于加载代理对象
-
interfaces
-
h:实现了
InvocationHandler
接口的对象
InvocationHandler
来自定义处理逻辑。 当动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
public interface InvocationHandler {
//当使用代理对象调用方法的时候实际会调用到这个方法
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
invoke
参数说明
-
:动态生成的代理类
-
method:与代理类对象调用的方法相对应
-
args
JDK 动态代理类实现步骤
定义一个接口及其实现类
自定义实现
InvocationHandler
并重写invoke
方法,在invoke
方法中会调用原生方法(被代理类的方法)并自定义一些处理逻辑
- 需要聚合一个代理类中真实Ojbcet对象成员变量
创建一个工厂类,新建工厂方法:通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象
定义一个接口及其实现类
public interface SendEmailService {
String send(String content);
}
public class SendEmailServiceImpl implements SendEmailService {
@Override
public String send(String content) {
System.out.println("发送邮件内容为 "+content);
return content;
}
}
自定义实现 InvocationHandler
并重写invoke
方法
public class JDKDynamicProxy implements InvocationHandler {
//代理类中的真实对象
private final Object object;
public JDKDynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用方法之前,可以添加自己的操作
System.out.println("开始发送邮件");
Object result = method.invoke(object, args);
//调用方法之后,可以添加自己的操作
System.out.println("结束发送邮件");
return result;
}
}
创建一个工厂类获取代理对象
public class ProxyFactory {
/**
* 通过Proxy.newProxyInstance()方法获取某个类的代理对象
*/
public static Object getProxy(Object target){
return Proxy.newProxyInstance(
//目标类的类加载器
target.getClass().getClassLoader(),
//代理需要实现的接口,可指定多个
target.getClass().getInterfaces(),
//代理对象对应的自定义 InvocationHandler
new JDKDynamicProxy(target)
);
}
}
测试
SendEmailService emailService = (SendEmailService)ProxyFactory.getProxy(new SendEmailServiceImpl());
emailService.send("JDK 动态代理实现");
输出结果为
开始发送邮件
发送邮件内容为 JDK 动态代理实现
结束发送邮件
CGLIB 动态代理机制
为了解决 JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类 的问题,可以用 CGLIB 动态代理机制来避免。CGLIB 通过继承方式实现代理,
- 在 CGLIB 动态代理机制中
MethodInterceptor
接口和Enhancer
类是核心
MethodInterceptor
并重写 intercept
方法,intercept
方法
public interface MethodInterceptor extends Callback{
// 拦截被代理类中的方法
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
intercept
方法参数说明
-
被代理的对象(需要增强的对象)
-
method:被拦截的方法(需要增强的方法)
-
args:方法入参
-
methodProxy:
CGLIB 动态代理类实现步骤
自定义实现
MethodInterceptor
并重写intercept
方法,intercept
方法用于拦截增强被代理类的方法(和 JDK 动态代理中的invoke
方法类似)通过
Enhancer
类的create()
创建代理类
添加相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
public class SendEmailService {
public String send(String content) {
System.out.println("发送邮件内容为 "+content);
return content;
}
}
自定义实现 MethodInterceptor
并重写 intercept
方法
public class MyMethodInterceptor implements MethodInterceptor {
/**
* @param object 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param args 方法入参
* @param methodProxy 用于调用原始方法
*/
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//调用方法之前,可以添加自己的操作
System.out.println("开始发送邮件");
Object result = methodProxy.invokeSuper(object,args);
//调用方法之后,可以添加自己的操作
System.out.println("结束发送邮件");
return result;
}
}
通过 Enhancer
类的 create()
创建代理类
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz){
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}
测试
SendEmailService proxy = (SendEmailService) CglibProxyFactory.getProxy(SendEmailService.class);
proxy.send("cglib 动态代理实现");
输出结果为
开始发送邮件
发送邮件内容为 cglib 动态代理实现
结束发送邮件
两者对比
另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此
-
灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类
-
另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的
-
-
JVM 层面
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)