服务bean无法在spring cglib代理中注入

时间:2016-02-01 16:32:19

标签: java proxy spring-aop cglib

我有一个注释

@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实际上是OuterServiceProxy$$EnhancerByCGLIB$$b0b63bb6由Cglib增强,但似乎outerServiceProxy只是直接调用String getRemoteHourRoomStatus()而不是通过回调并调用TargetSource,所以service为空。但这没有意义!

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

更奇怪的是,如果没有public modifer,相同的代码在我的PC中运行良好,但NPE在公司测试环境中抛出。

1 个答案:

答案 0 :(得分:2)

这是诀窍:如果覆盖类与定义重写方法的类相同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的规范细节。