题
让我们假设我们已经得到了下列代码:
public class Maintainer {
private Map<Enum, List<Listener>> map;
public Maintainer() {
this.map = new java.util.ConcurrentHashMap<Enum, List<Listener>>();
}
public void addListener( Listener listener, Enum eventType ) {
List<Listener> listeners;
if( ( listeners = map.get( eventType ) ) == null ) {
listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>();
map.put( eventType, listeners );
}
listeners.add( listener );
}
}
这段代码是什么但有一点改善监听的模式,其中每个监听说是什么类型的事件很感兴趣,并提供方法保持一个并发的地图,这些关系。
起初,我想这种方法是通过我自己的注释框架,但是撞到砖墙的各种注释的限制(例如你不能拥有 java。郎。Enum 如注释的参数,还有一个集中的各类装入器问题),因此决定使用弹簧。
谁能告诉我怎么做我Spring_ify_这个吗?什么我想要实现的是:
1.定义 维护者 类作为春季豆。
2.让它使各种各样的听众能够注册自己 维护者 通过XML的采用 addListener 法。弹簧医生,也没有谷歌都是很慷慨的例子。
有没有办法实现这很容易吗?
解决方案
会是什么错误的做喜欢的东西如下:
定义的'维护者'接口与addListener(Listener,Enum)的方法。
创建一个DefaultMaintainer类(如上),实现维护者。
然后,在每个监听器类,注入'维护者的接口(constructor注可能是一个好的选择)。听众可以那么登记册本身的维护者。
另外,我不是100%清楚到底是什么你的困难是与春天的时刻!:)
其他提示
稍offtopic(因为这不是关于春天),但有一个竞争条件在您的执行情况的AddListener:
if( ( listeners = map.get( eventType ) ) == null ) {
listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>();
map.put( eventType, listeners );
}
listeners.add( listener );
如果两个线电话这种方法在同一时间(一个事件的类型,以前有没有听众),地图。获得(eventType)将返回null在线,每个线程将创建自己的CopyOnWriteArrayList(每个含有一个单一的监听),一个线程将取代表创建的通过其他,第一个监听器会被遗忘。
为了解决这个问题,改变:
private Map<Enum, List<Listener>> map;
...
map.put( eventType, listeners );
为:
private ConcurrentMap<Enum, List<Listener>> map;
...
map.putIfAbsent( eventType, listeners );
listeners = map.get( eventType );
1)定义的维护者类作为春季豆。
标准的弹簧法适用于:
<bean id="maintainer" class="com.example.Maintainer"/>
2)使所有各种各样的听众能够自己注册来维护者通过XML通过使用addListener方法。弹簧医生,也没有谷歌都是很慷慨的例子。
这是棘手。你的 可能 使用 MethodInvokingFactoryBean
单独通话 maintainer#addListener
, 是这样的:
<bean id="listener" class="com.example.Listener"/>
<bean id="maintainer.addListener" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="maintainer"/>
<property name="targetMethod" value="addListener"/>
<property name="arguments">
<list>
<ref>listener</ref>
<value>com.example.MyEnum</value>
</list>
</property>
</bean>
然而,这是笨重的,并且可能容易出错。我尝试类似的一个项目,并且创建了一个弹簧用类帮助,而不是。我没有的源代码可用的时刻,所以我将描述如何实现我做了什么。
1)"重构"的活动类型听到 MyListener
接口
public interface MyListener extends Listener {
public Enum[] getEventTypes()
}
这改变的登记方法
public void addListener(MyListener listener)
2)创建春助手类,认定所有相关的听众在这方面,并呼吁维护者#addListener为每个监听发现。我会开始 BeanFilteringSupport
, ,并且还实施 BeanPostProcessor
(或 ApplicationListener
)注册的豆后所有豆子已经被初始化。
你说"...你不能拥有java。郎。Enum为" 注param..."
我认为你是错误的。我最近使用的一个项目是这样的:
public @interface MyAnnotation {
MyEnum value();
}
谢谢你所有的答案。第一,一个快速跟踪所有的答案。
1.(alexvictor)是的,你可以有具体的 enum 如注释的参数,但不是 java。郎。Enum.
2.回答提供flicken是正确的,但不幸的是有点吓人。我不是春天的专家,但做的事情,这种方法(创建方法更容易春天访问),这似乎是一位矫枉过正,为的是 MethodInvokingFactoryBean 解决方案。虽然我想表达我的真诚感谢您的时间和精力。
3.答案由菲尔是一位不同寻常(而不是注射侦听豆,注入它的维护者!), 但是,我相信,最干净的所有可用的。我想我会走这条道路。
再次,非常感谢你对你有所帮助。