我有一个注释

@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();
    }
}

我想代理的豆子
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为null。但这没有意义!

当我添加public修饰符时,public String getRemoteHourRoomStatus()一切正常。

更奇怪的是,没有public修饰符,相同的代码在我的PC上运行正常,但是在公司测试环境中抛出了NPE。

最佳答案

这是窍门:如果覆盖的类由与定义覆盖的方法的类相同的ClassLoader加载,则VM仅认为包专用方法被覆盖。

这意味着对于两个具有覆盖的包专用方法的类,例如:

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的规范细节要少。

07-26 04:26