[SPRING] Spring Bean 사용자 정의 범위 JMS
SPRINGSpring Bean 사용자 정의 범위 JMS
Spring Framework를 사용하여 DefaultMessageListenerContainer를 사용하여 JMS 큐에서 메시지를 동시에 소비한다. 들어오는 각 메시지에 대해 자동으로 실행되는 bean의 새로운 인스턴스를 생성 할 수있는 능력을 원합니다. scope = "prototype"을 설정하는 것이 효과가 있지만 작업을 수행하지 않는 것 같습니다. JMS 메시지 당 새로운 인스턴스를 생성하는 커스텀 빈 범위를 아는 사람이 있습니까? HTTP 요청에 대한 "요청"범위와 비슷합니까?
필자는 com.sample.TestListener "BeanFactoryAware"를 만든 다음 내 onMessage에서 getBean ( "foo")을 수행 할 수 있음을 알고 있지만 내 코드에 Spring 의존성을 넣는 것을 피하려고합니다.
어떤 도움을 주셔서 미리 감사드립니다!
아래의 예제에서 "com.sample.Foo"라는 새로운 인스턴스와 메시지가 들어올 때마다 그 안에 삽입 된 모든 빈을 원한다.
<bean id="consumer"
class="com.sample.TestListener">
<constructor-arg ref="foo" />
</bean>
<!--Configures the Spring Message Listen Container. Points to the Connection
Factory, Destination, and Consumer -->
<bean id="MessageListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="CachedConnectionFactory" />
<property name="destination" ref="Topic" />
<property name="messageListener" ref="consumer" />
<property name="concurrency" value="10"/>
</bean>
<bean id="foo" class="com.sample.Foo">
<property name="x" ref="xx" />
<property name="y" ref="yy" />
<property name="z" ref="zz" />
</bean>
해결법
-
==============================
1.이렇게하는 사용자 정의 범위를 작성하는 것은 꽤 쉽습니다 ...
이렇게하는 사용자 정의 범위를 작성하는 것은 꽤 쉽습니다 ...
public class CustomScope implements Scope, BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { String name = "myScope"; beanFactory.registerScope(name, this); Assert.state(beanFactory instanceof BeanDefinitionRegistry, "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used."); BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = beanFactory.getBeanDefinition(beanName); if (name.equals(definition.getScope())) { BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, false); registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition()); } } } @Override public Object get(String name, ObjectFactory<?> objectFactory) { return objectFactory.getObject(); // a new one every time } @Override public String getConversationId() { return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object remove(String name) { return null; } @Override public Object resolveContextualObject(String arg0) { return null; } } public class Foo implements MessageListener { private Bar bar; public void setBar(Bar bar) { this.bar = bar; } @Override public void onMessage(Message message) { System.out.println(bar.getId()); } } @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class FooTests { @Autowired private Foo foo; @Test public void test() { Message message = mock(Message.class); foo.onMessage(message); foo.onMessage(message); } }
샘플 컨텍스트 ...
<bean class="foo.CustomScope" /> <bean id="baz" class="foo.BazImpl" scope="myScope" /> <bean id="bar" class="foo.BarImpl" scope="myScope"> <property name="baz" ref="baz" /> </bean> <bean id="foo" class="foo.Foo"> <property name="bar" ref="bar" /> </bean>
참고 :이 간단한 범위를 사용하면 참조 된 모든 bean을 범위에 넣어야합니다 (위의 bar 및 baz). 참조 된 모든 bean이 범위를 상속 받도록 만들 수는 있지만 약간의 작업이 필요합니다. 즉, 스프링 배치의 StepScope에서이를 수행하는 방법의 예가 있습니다.
참고 # 2 이것은 모든 메소드 호출에 대해 새로운 인스턴스를 얻게 될 것이다. 여러 메소드를 호출하면 각 호출에 대해 새 bean을 얻습니다. onMessage 내의 모든 호출에서 동일한 인스턴스를 사용할 수 있도록 범위를 지정하려면 더 많은 트릭을 추가해야합니다.
편집하다: onMessage () 내에서 인스턴스에 대한 여러 호출을 지원하는 몇 가지 업데이트가 있습니다.
private final ThreadLocal<Map<String, Object>> holder = new ThreadLocal<Map<String, Object>>(); ... @Override public Object get(String name, ObjectFactory<?> objectFactory) { Map<String, Object> cache = this.holder.get(); if (cache == null) { cache = new HashMap<String, Object>(); this.holder.set(cache); } Object object = cache.get(name); if (object == null) { object = objectFactory.getObject(); cache.put(name, object); } return object; } public void clearCache() { this.holder.remove(); }
자, 당신은 캐시를 지워야 만합니다 ...
@Override public void onMessage(Message message) { try { System.out.println(bar.getId()); System.out.println(bar.getId()); } finally { this.scope.clearCache(); } }
그러나 AOP @After 조언을 통해서도 청취자를 완전히 깨끗하게 유지할 수 있습니다.
-
==============================
2.Spring과 함께 제공되는 SimpleThreadScope 구현 사용
Spring과 함께 제공되는 SimpleThreadScope 구현 사용
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/context/support/SimpleThreadScope.html
from https://stackoverflow.com/questions/15415688/spring-bean-custom-scope-jms by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring JMS와 Oracle AQ (0) | 2019.05.11 |
---|---|
[SPRING] executeSqlScript가 PL / SQL 용 Spring 블록과 함께 실패합니다. (0) | 2019.05.11 |
[SPRING] Classpath를 가진 Spring Boot 실행 가능한 Jar (0) | 2019.05.11 |
[SPRING] 봄 / JTA / JPA DAO 통합 테스트가 롤백되지 않습니까? (0) | 2019.05.11 |
[SPRING] RequestContextHolder와 같은 Response의 홀더 클래스가없는 이유는 무엇입니까? (0) | 2019.05.11 |