gpt4 book ai didi

java - Spring Bean 自定义作用域 JMS

转载 作者:搜寻专家 更新时间:2023-11-01 03:08:09 24 4
gpt4 key购买 nike

我正在使用 Spring Framework 同时使用 DefaultMessageListenerContainer 从 JMS 队列中获取消息。我希望能够为传入的每条消息创建 Autowiring 的新 bean 实例。我认为设置 scope="prototype"会起作用,但它似乎不起作用。有谁知道自定义 bean 作用域可以为每个 JMS 消息创建新实例?很像 HTTP 请求的“请求”范围吗?

我意识到我可以创建 com.sample.TestListener“BeanFactoryAware”,然后在我的 onMessage 中执行一个 getBean(“foo”),但我想避免将 Spring 依赖项放入我的代码中。

在此先感谢您的帮助!

下面的示例,我想要一个“com.sample.Foo”的新实例,并且每次收到消息时都会将所有 bean 注入(inject)其中。

<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>

最佳答案

编写自定义范围来执行此操作非常容易...

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 放入作用域中(上面的 baz)。您可以使所有引用的 bean 都继承范围,但这需要一些工作。也就是说 - 在 spring-batch 的 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 建议中完成,以保持听众完全干净。

关于java - Spring Bean 自定义作用域 JMS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15415688/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com