java代理的一个小坑
工作中一个业务逻辑需要用到java的代理,java代理需要实现InvocationHandler接口,并覆写invoke方法:
public class TestInvocationHandler : implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
}
}
这都是通用写法,不再赘述。但是在运行过程中碰到一个报错:
Class com.xxx.handler.TestInvocationHandler can not access a member of class com.xxx.biz.TestAPI with modifiers "public abstract"
搜索也没找到解决办法,最后在startoverflow找到一个规避办法,在invoke方法中增加
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.setAccessible(true);
...
}
问题还真解决了!不过这个答案也启发了我继续探索这个问题的原因。
在代码中TestInvocationHandler在handler package下,而业务接口定义在biz package下,而我发现定义接口时,接口的访问域没填,是java语言默认值。
interface TestAPI {
}
设置interface的访问域为public,不需要method.setAccessible(true);
,问题同样也解决了!
public interface TestAPI {
}
但为什么呢?继续查找资料,参考深入java(类)接口默认修饰符问题,在interface没指定修饰符的情况下默认是frendly,包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类)。
所以handler包里TestInvocationHandler不能访问biz包里的TestAPI就不奇怪了。奇怪的是编译过程没有报错。
再深入去想,java的代理机制就是在运行时才决定接口的具体实现,不是在编译过程中确定的。整个过程也就不奇怪了。