Spring CGLIB代理中服务bean注入失败

3
我有一个注释。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PartnerProxy {
}

并提供一些建议

@Component
@Aspect
public class AnnotationAdvice {

    @Around("@annotation(PartnerProxy)")
    public Object pc(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed();
    }
}

我想要代理的Bean

public class OuterServiceProxy {

    private IRoomStatusService service;
    ... another properties

    String getRemoteHourRoomStatus(){
        return service.echo();
    }
    @PartnerProxy
    public void hello() {
    }
    ...getters & setters

有一个属性IRoomStatusService service,这是关键点。 首先如果我在Spring XML文件中声明了OuterServiceProxy

<bean id="outerServiceProxy" class="aop.jg.OuterServiceProxy">
        <property name="service" ref="service"/>
    </bean>

当调用outerServiceProxy.getRemoteHourRoomStatus()方法时,会抛出NPE异常。我调试到了该行代码[1]。

String getRemoteHourRoomStatus(){
        return service.echo();  [1]
    } 
service 为空,但是 outerServiceProxy 实际上是由 Cglib 增强的 OuterServiceProxy$$EnhancerByCGLIB$$b0b63bb6,但是似乎 outerServiceProxy 直接调用了 String getRemoteHourRoomStatus() 而不是通过回调和调用 TargetSource,因此 service 为空。但这没有意义!当我添加 public 修饰符 public String getRemoteHourRoomStatus() 时,一切都很好。

更奇怪的是,没有 public 修饰符,在我的个人电脑上同样的代码运行良好,但在公司的测试环境中却抛出 NPE。

1个回答

3
以下是诀窍:只有在加载定义被覆盖方法的类的ClassLoader与覆盖它的类相同时,虚拟机才会认为一个包私有方法被覆盖。
这意味着对于两个具有被覆盖包私有方法的类,例如:
public class Foo { String qux() { return "foo"; } }
public class Bar extends Foo { @Override String qux() { return "bar"; } }

在哪里

Foo.class.getClassLoader() != Bar.class.getClassLoader()

以下是相关行为可以观察到:

Foo foo = new Bar();
assertThat(foo.qux(), is("foo"));
assertThat(((Bar) foo).qux(), is("bar"));

原因是运行时包不相同,因此不同运行时包的包私有方法不会互相覆盖。这不仅是cglib的限制,也是JVM规范的细节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接