2008-09-16 2 views
2

Давайте предположим, что мы получили следующий Java-код:Карта Перечисления и инъекции зависимостей весной 2,5

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.

Может ли кто-нибудь сказать мне, как мне Spring_ify_ это? То, что я хочу достичь:
1. Определить Материнское предприятие класс как фасоль.
2. Сделайте так, чтобы всевозможные слушатели смогли зарегистрироваться до Сопровождающий через XML с помощью addListener. Spring doc и Google очень щедры в примерах.

Есть ли способ достичь этого легко?

ответ

2

Что бы неправильно с делать что-то вроде следующего:

Определение интерфейса «» MAINTAINER с AddListener метод (Слушатель, Enum).

Создайте класс DefaultMaintainer (как указано выше), который реализует Maintainer.

Затем в каждом классе прослушивателя «вводят» интерфейс Maintainer (инжекция конструктора может быть хорошим выбором). Затем слушатель может зарегистрировать себя в Maintainer.

кроме этого, я не на 100% не понимаю, с чем именно связана ваша трудность с весной на данный момент! :)

0

Вы сказали, что «... вы не можете иметь java.lang.Enum как» аннотацию парам ...»

Я думаю, вы не правы в этом. У меня в последнее время используется на проекте что-то вроде этого:.

public @interface MyAnnotation { 
    MyEnum value(); 
} 
+0

Ну, это именно то, что я сказал, - "вы не можете иметь java.lang.Enum, как аннотации пары". Я спрашивал, как мне это сделать весной? – mindas 2008-09-16 15:26:51

1

1) Определить класс Maintainer как Spring бина

Стандартный синтаксис Spring применяется:

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

2) Сделать так, чтобы все виды слушателей смогут зарегистрировать себя MAINTAINER через XML, используя метод добавления слушателя. Spring doc и 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) Создать весенний вспомогательный класс, который находит все соответствующие слушателей в контексте , и вызывает поддержку # addListener для каждого найденного слушателя. Я бы начал с BeanFilteringSupport, а также реализовать BeanPostProcessor (или ApplicationListener), чтобы зарегистрировать bean-компоненты после того, как все компоненты были созданы.

0

Спасибо всем за ответы. Во-первых, быстрое отслеживание всех ответов.
1. (alexvictor) Да, у вас может быть бетон enum в качестве аннотации параметра, но не java.lang.Enum.
2. Ответ, предоставленный flicken, верен, но, к сожалению, немного страшен. Я не эксперт по Spring, но делаю так (создавая методы для облегчения доступа Spring), это, кажется, немного перебор, так же как и решение MethodInvokingFactoryBean. Хотя я хотел выразить искреннюю благодарность за ваше время и усилия.
3. Ответ от Филла немного необычен (вместо того, чтобы вставлять бин слушателя, вводить его сопровождающего!), Но, я считаю, самый чистый из всех доступных. Думаю, я пойду по этому пути.

Еще раз большое вам спасибо за помощь.

2

Слегка оффтоп (как это не про Spring), но есть условие гонки в вашей реализации AddListener:

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

Если два потока вызывает этот метод в то же время (для типа события, которые ранее не было слушателей), map.get (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); 
+0

Хороший улов, спасибо большое! – mindas 2008-09-22 14:08:32

Смежные вопросы