spring singleton bean字段未填充
我需要一个服务(单身适合)与一些内部字段,如一个挂起的线程列表(是的一切都被编写为线程安全)问题是,如果我@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)
你好奇还是有一些真正的问题? 不过这是一个解释。
当使用CGLIB代理类时,Spring将创建一个名为myService$EnhancerByCGLIB
的子类。 此增强类将覆盖一些(如果不是全部)业务方法,以应用实际代码的横切关注点。
这真是一个惊喜。 这个额外的子类不会调用基类的super
方法。 相反,它会创建myService
第二个实例并委托给它。 这意味着您现在有两个对象:您的真实对象和指向(包装)它的CGLIB增强对象。
增强类只是一个虚拟代理。 它仍然具有与基类相同的字段(从中inheritance)但不使用它们。 当你在myService$EnhancerByCGLIB
对象上调用addToList()
时,它将首先应用一些AOP逻辑,调用myService
addToList()
(它包装)并在返回时应用剩余的AOP逻辑。 永远不会触及myService$EnhancerByCGLIB.list
字段。
为什么Spring不能使用同一个类并通过super
委托? 我想简单来说:首先创建“ 原始 ”bean然后在后处理期间应用AOP代理。
“在调用getSomething()之前,某个人肯定会填充此字段”
有人吗? 不,春豆厂。 如果您不配置它,将不会填充任何内容。
并非每个bean都需要受到Spring的控制。 听起来你想拥有一个List
,客户端可以以线程安全的方式添加和删除项目。 如果是这样,请删除@Autowired
注释,创建新List
,并公开要添加和删除的方法。
我建议使用新的并发集合中的List。
CGLIB将代理受保护的getter。
所以你可以:
@Autowired private Monitor monitor; protected Monitor getMonitor() { return monitor; } public List getSomething(){ return getMonitor().getList(); }
将代理getMonitor()来调用已注入监视器的另一个实例上的getMonitor()。