문제

다음과 같은 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을 사용하기로 결정했습니다.

누구든지 이것을 Spring_ify_하는 방법을 말해 줄 수 있습니까?내가 달성하고 싶은 것은 다음과 같습니다.
1.정의하다 유지관리자 클래스를 Spring Bean으로 사용합니다.
2.모든 종류의 청취자가 등록할 수 있도록 만드세요. 유지관리자 XML을 통해 addListener 방법.Spring doc이나 Google은 예제에 있어서 매우 관대합니다.

이것을 쉽게 달성할 수 있는 방법이 있나요?

도움이 되었습니까?

해결책

다음과 같은 작업을 수행하면 무엇이 문제가 될까요?

addListener(Listener, Enum) 메소드를 사용하여 'Maintainer' 인터페이스를 정의합니다.

유지관리자를 구현하는 DefaultMaintainer 클래스(위와 같이)를 만듭니다.

그런 다음 각 Listener 클래스에서 유지관리자 인터페이스를 '주입'합니다(생성자 주입이 좋은 선택일 수 있음).그러면 청취자는 유지관리자에 등록할 수 있습니다.

그 외에는 현재 Spring에 대한 귀하의 어려움이 정확히 무엇인지 100% 명확하지 않습니다!:)

다른 팁

약간 주제에서 벗어났지만(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 );

1) 유지관리자 클래스를 Spring 빈으로 정의합니다.

표준 Spring 구문이 적용됩니다.

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

2) addListener 메소드를 이용하여 모든 종류의 Listener들이 XML을 통해 Maintenanceer에 자신을 등록할 수 있도록 만들어준다.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) 컨텍스트에서 모든 관련 리스너를 찾는 Spring 도우미 클래스를 생성하고 발견된 각 리스너에 대해maintainer#addListener를 호출합니다.나는부터 시작할 것이다 BeanFilteringSupport, 또한 구현 BeanPostProcessor (또는 ApplicationListener) 모든 Bean이 인스턴스화된 후 Bean을 등록합니다.

당신은 "...java.lang.enum을 "주석 매개 변수 ..."로 가질 수 없습니다.

나는 당신이 틀렸다고 생각합니다.나는 최근에 다음과 같은 프로젝트를 사용했습니다.

public @interface MyAnnotation {
    MyEnum value();
}

답변해 주셔서 감사합니다.첫째, 모든 답변에 대한 빠른 후속 조치입니다.
1.(alexvictor) 예, 콘크리트를 사용할 수 있습니다. 열거형 주석 매개변수로 사용되지만 그렇지 않음 java.lang.Enum.
2.flicken이 제공한 답변은 정확하지만 불행히도 조금 무섭습니다.나는 Spring 전문가는 아니지만 이런 방식으로 작업을 수행하는 것(더 쉬운 Spring 액세스를 위한 메소드 생성)은 약간 과잉인 것 같습니다. 메소드InvokingFactoryBean 해결책.귀하의 시간과 노력에 진심으로 감사를 표하고 싶었지만.
삼.Phill의 답변은 약간 특이하지만(리스너 빈을 주입하는 대신 유지관리자를 주입합니다!), 가능한 모든 것 중에서 가장 깔끔하다고 생각합니다.저는 이 길로 갈 것 같아요.

다시 한 번 귀하의 도움에 큰 감사를 드립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top