服务 bean 无法注入 spring cglib 代理

Service bean failed to inject in spring cglib proxy

我有注释

@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为null。但这没有意义!

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

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

诀窍是:如果重写 class 由与定义重写的方法。

这意味着对于两个 class 具有覆盖包私有方法的 es,例如:

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