2012-07-20 98 views
2

我需要一个服务(单身符合)与一些内部字段,如待处理线程列表(是的一切都写成线程安全)问题是,如果我@autowire这个bean,字段似乎是空的。调试我发现代理正确地绑定到实例(字段CGLIB$CALLBACK_X正确链接到填充的bean)并填充字段,但它提供的字段为空。春天单身豆字段不填充

以下几行代码给出了我正在谈论的一般概念。

@Service 
public class myService{ 

    @Autowired 
    private Monitor monitor; 

    public List getSomething(){ 
     return monitor.getList(); 
    } 
} 


@Service 
public class myStatefulService{ 

    //This field will be populated for sure by someone before getSomething() is called 
    private List list; 

    public synchronized List getSomething(){ 
     return this.list; 
    } 

    //Called by other services that self inject this bean 
    public synchronized void addToList(Object o){ 
     this.list.add(o); 
    } 
} 

中的GetList通话过程中调试变量monitor我得到

monitor => instance of correct class 
fields: 
    CGLIB$BOUND => true 
    CGLIB$CALLBACK_0.advised => proxyFactory (correct) 
    CGLIB$CALLBACK_1.target (reference to the correct instance of myStatefulService class) 
     fields: 
      list => [.........] (correctly populated) 
    CGLIB$CALLBACK_2 ..... 
    ...... 
    ...... 
    ...... 
    list => [] (the list that would be populated is empty instead) 

回答

8

你好奇还是有一些真正的问题?尽管如此,这是一个解释。

当使用CGLIB代理类时,Spring将创建一个名为myService$EnhancerByCGLIB的子类。这个增强的类将覆盖一些(如果不是全部)商业方法,以便在您的实际代码中应用横切关注点。

这里是真正的惊喜。这个额外的子类不会调用基类的super方法。相反,它创建myService的第二个实例并委托给它。这意味着你现在有两个对象:你的真实对象和CGLIB增强对象指向(包装)它。

增强型类仅仅是一个虚拟代理。它仍然有和你的基类相同的字段(从它继承),但它们不被使用。当您在myService$EnhancerByCGLIB对象上调用addToList()对象时,它将首先应用一些AOP逻辑,调用addToList()myService(将其封装),并在返回时应用剩余的AOP逻辑。 myService$EnhancerByCGLIB.list字段永远不会被触及。

为什么春不能使用相同的班级并通过super委托?我想为了简单起见:首先创建“raw”bean,然后在后处理期间应用AOP代理。

4

“该字段会被别人getSomething填充之前肯定()被称为”

通过别人?不,春豆厂。如果您不配置它,则不会填充任何内容。

不是每个bean都需要受Spring的控制。这听起来像你想有一个List客户端可以添加和删除项目以线程安全的方式。如果是这样,请删除@Autowired注释,创建新的List,并公开要添加和删除的方法。

我建议从新的并发集合列表。

+0

对不起,列表中的@autowired是一个打字错误....一切都在Spring的控制之下,“某人”是一种响应客户端动作的其他服务......所以客户端使用其他服务向列表添加元素。带有列表的服务包含逻辑并定期在列表上工作,所以我需要成为一个singleton可注入有状态bean =) – Gnappuraz 2012-07-20 14:22:18

+0

是的,我提供了添加元素到列表的方法,但是当列表被读取时它也是空的,如果代理指向的实例已正确填充它。 – Gnappuraz 2012-07-20 14:29:01

+0

为什么你需要一个代理?我会说这是一个不需要由Spring控制的对象的例子。只是实例化一个新的并继续下去。 – duffymo 2012-07-20 16:50:26

0

CGLIB将代理受保护的获得者。

所以,你可以有:

@Autowired 
private Monitor monitor; 

protected Monitor getMonitor() { return monitor; } 

public List getSomething(){ 
    return getMonitor().getList(); 
} 

getMonitor()将被代理到在具有显示器注入另一实例调用getMonitor()。