代码之家  ›  专栏  ›  技术社区  ›  mindas

Spring2.5中的枚举和依赖注入映射

  •  2
  • mindas  · 技术社区  · 16 年前

    假设我们有下面的Java代码:

    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.Lang.EnUm 作为注释参数,还有一组不同的类加载器问题),因此决定使用Spring。

    有人能告诉我,我该怎么解释这个吗?我想要实现的是:
    1。定义 保持器 像豆子一样上课。
    2。使所有类型的听众都能够注册到 保持器 通过使用XML 加法器 方法。SpringDoc和Google都是非常慷慨的例子。

    有没有一种方法可以轻松实现这一目标?

    5 回复  |  直到 8 年前
        1
  •  2
  •   user7094    16 年前

    这样做会有什么问题:

    使用addListener(Listener,Enum)方法定义“Maintainer”接口。

    创建一个实现Maintainer的DefaultMaintainer类(如上所述)。

    然后,在每个侦听器类中,“inject”维护者接口(构造函数注入可能是一个不错的选择)。然后,侦听器可以向维护者注册自己。

    除此之外,我还不完全清楚你现在对春天有什么困难!:)

        2
  •  2
  •   finnw    16 年前

    稍微偏离主题(因为这不是关于Spring的),但是在您的addListener实现中有一个争用条件:

      if( ( listeners = map.get( eventType ) ) == null ) {
         listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>();
         map.put( eventType, listeners );
      }
      listeners.add( listener );
    

    如果两个线程同时调用此方法(对于以前没有侦听器的事件类型),map.get(event type)将在两个线程中返回空值,每个线程将创建自己的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 );
    
        3
  •  1
  •   flicken    16 年前

    1)将Maintainer类定义为SpringBean。

    标准弹簧语法适用:

    <bean id="maintainer" class="com.example.Maintainer"/>
    

    2)使用addListener方法,使各种监听器能够通过XML注册到维护者。SpringDoc和Google都是非常慷慨的例子。

    这更棘手。你 能够 使用 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>
    

    然而,这是不易操作的,并且可能容易出错。我在一个项目中尝试了类似的方法,并创建了一个Spring实用程序类来帮助解决这个问题。我现在没有可用的源代码,所以我将描述如何实现我所做的。

    1)将侦听的事件类型重构为 MyListener 界面

    public interface MyListener extends Listener {
      public Enum[] getEventTypes()
    }
    

    将注册方法更改为

    public void addListener(MyListener listener)
    

    2)创建在上下文中查找所有相关侦听器的SpringHelper类,并为找到的每个侦听器调用Maintainer AddListener。我会从 BeanFilteringSupport ,并执行 BeanPostProcessor (或) ApplicationListener )在所有bean实例化之后注册bean。

        4
  •  0
  •   Alexandre Victoor    16 年前

    你说“……”不能将java.lang.enum设置为“ 注释参数…”

    我认为你在这方面是错的。我最近在一个类似这样的项目中使用过:

    public @interface MyAnnotation {
        MyEnum value();
    }
    
        5
  •  0
  •   mindas    16 年前

    谢谢大家的回答。首先,快速跟进所有答案。
    1。(亚历克维克多)是的,你可以有具体的 枚举 作为注释参数,但不是 Java.Lang.EnUm .
    2。Flicken提供的答案是正确的,但不幸的是有点吓人。我不是Spring专家,但这样做(为更容易的Spring访问创建方法)似乎有点过分,就像 有条不紊的行为 解决方案。尽管我想对你的时间和努力表示衷心的感谢。
    三。Phill的答案有点不寻常(与其注入ListenerBean,不如注入其维护程序!)但是,我相信,是最干净的。我想我会沿着这条路走。

    再次感谢你的帮助。