利用java.lang.reflect.Proxy 实现代理

本文介绍了一种利用Java反射机制中的Proxy类来减少代码耦合的方法。通过创建自定义拦截器并结合接口,实现了对类成员变量和服务的自动注入,从而避免了手动调用扫描方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结合上一篇文章([url=http://leh627.iteye.com/blog/828434]自定义annotation 实现注入功能[/url]),里面模拟了一个拦截器。
发现在使用的时候都需要去调用SimilarToTheInterceptor.scanAllFieldsAndMethods 方法,
如果说有多个action需要注入,很显然这是种不好的设计。
TestAction action = new TestAction();
SimilarToTheInterceptor.scanAllFieldsAndMethods(action);// 模拟拦截器功能
action.saveDate1();
于是我想到使用java.lang.reflect.Proxy 去实现这个拦截器功能

正对前一篇文章的代码下面几个类需要改变
1.SimilarToTheInterceptor 该名称 ScanHelper 内容保持不变
2.增加一个新类,用来实现 拦截功能

package com.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Handler implements InvocationHandler {

private Object obj;

public Handler(Object obj) {
this.obj = obj;
}

public static Object newInstance(Object obj) {
System.out.println(obj.getClass().getName());

return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()

.getClassLoader(), obj.getClass().getInterfaces(),

new Handler(obj));

}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
if(obj!=null){
ScanHelper.scanAllFieldsAndMethods(obj);// 注入
result = method.invoke(obj, args);
}
return result;
}

}


3,增加一个接口Action,然后TestAction去实现这个接口(由于proxy 必须要一个接口)

public interface Action {
public void saveDate1();
public void saveDate2();
}

3 ,测试

package com.test;

public class Main {
public static void main(String[] args) {
TestAction a = new TestAction();
Action action = (Action) Handler.newInstance(a);
action.saveDate1();
action.saveDate2();
}
}


4.结果
==========Saved======TestService_1 class was invoked
==========Saved======TestService_2 class was invoked

这样实现就很好的降低了耦合
<think>好的,我需要解决用户遇到的Java反射问题,具体是访问java.lang.reflect.Proxy.h字段时出现的InaccessibleObjectException错误。用户提到错误信息是模块java.base没有将java.lang.reflect开放给未命名模块,导致无法访问受保护的InvocationHandler字段。我需要结合提供的引用信息来找到解决方案。 首先,根据引用[3]和[4],这个错误是由于Java 9引入的模块系统加强了封装,限制了反射访问内部类和方法。解决方案通常涉及修改启动参数,使用--add-opens来开放相应的模块。例如,引用[4]和[5]建议添加--add-opens参数来允许访问。 接下来,我需要明确用户的具体情况。他们可能在尝试通过反射访问Proxy类的h字段,这属于java.base模块中的java.lang.reflect包。根据错误信息,正确的解决方案应该是添加对应的--add-opens参数,如引用[5]提到的:--add-opens java.base/java.lang.reflect=ALL-UNNAMED。 此外,引用[4]中还提到了可能需要同时开放java.lang包,所以可能需要添加多个参数,如示例中的参数组合。需要检查用户的启动参数是否正确配置,是否覆盖了所有需要的模块和包。 另外,如果用户使用的是Spring Boot或其他框架,可能需要通过特定的配置文件或启动脚本添加这些参数,比如在IDE的运行配置中,或者在Maven或Gradle的配置文件中设置JVM参数。 还需要提醒用户注意不同JDK版本的兼容性问题,并建议在可能的情况下升级依赖库,确保它们支持新的模块系统。如果用户无法修改启动参数,可能需要寻找替代的反射方法或避免直接访问内部字段,但这可能较难实现。 最后,总结解决方案的步骤,确保用户能逐步操作,并解释每个步骤的原因,帮助他们理解问题根源。同时,生成相关问题,帮助用户进一步了解模块系统和反射相关的问题。</think>### 分步解决方案 #### 问题分析 在Java 9及以上版本中,模块系统(Jigsaw)引入了强封装机制,默认阻止反射访问未明确开放的内部类或字段[^3][^4]。错误信息 `Unable to make field protected java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.h accessible` 表明程序尝试通过反射访问 `Proxy` 类的受保护字段 `h`,但 `java.base` 模块未将 `java.lang.reflect` 包开放给未命名模块(如用户项目的模块)[^1][^5]。 --- #### 解决方案 ##### 方法1:添加JVM启动参数 通过添加 `--add-opens` 参数,强制开放目标模块和包,允许反射访问。 **具体步骤**: 1. **命令行/Maven/Gradle**: ```bash java --add-opens java.base/java.lang.reflect=ALL-UNNAMED -jar your_application.jar ``` 2. **IDE配置(如IntelliJ/Eclipse)**: - 打开运行配置(Run Configuration)。 - 在 `VM options` 中添加: ``` --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED # 若同时涉及其他包 ``` - 保存后重新运行程序。 ##### 方法2:升级依赖库 某些旧版库(如ASM、Spring等)可能未适配Java模块系统。检查并升级到支持模块化访问的版本[^4]。 ##### 方法3:代码层绕过(不推荐) 尽量避免直接反射访问内部字段 `Proxy.h`,改用标准API(如 `Proxy.getInvocationHandler()` 方法)获取 `InvocationHandler`。 --- #### 解释与注意事项 - **`--add-opens` 参数作用**:允许未命名模块(即用户项目)通过反射访问指定模块的私有成员。 - **安全性**:开放模块会降低封装性,需评估是否必要。 - **兼容性**:若需兼容JDK 8,可添加条件化启动参数。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值