首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Camel bean组件调用@命名/@依赖bean的缓存实例

Camel bean组件调用@命名/@依赖bean的缓存实例
EN

Stack Overflow用户
提问于 2018-06-29 20:23:09
回答 1查看 266关注 0票数 1

在我们的应用程序中,我们在camel-cdi EAP7.1环境中使用带有JBoss组件的Apache。在Apache升级到实际版本之后,应用程序开始在并行执行中不正确地运行。

我发现,bean组件总是调用同一个实例。据我理解,带@Dependent作用域的bean应该始终是每个CDI查找的新实例。

我尝试过端点参数cache=false,它应该是默认的,但是行为保持不变。还尝试指定@Dependent,这也应该是默认的。

附加MCVE,在Apache 2.20.0和更新程序上失败。在2.19.5和更高版本中工作得很好。完全可复制的项目论吉乌布

代码语言:javascript
复制
@ApplicationScoped
@Startup
@ContextName("cdi-context")
public class MainRouteBuilder extends RouteBuilder {
    public void configure() throws Exception {
        from("timer:test")
                .to("bean:someDependentBean?cache=false");
    }
}

@Named
//@Dependent //Dependent is default
public class SomeDependentBean implements Processor {
    private int numOfInvocations = 0;
    private static Logger log = LoggerFactory.getLogger(SomeDependentBean.class);

    public void process(Exchange exchange) throws Exception {
        log.info("This is: "+toString());
        numOfInvocations++;
        if (numOfInvocations!=1){
            throw new IllegalStateException(numOfInvocations+"!=1");
        } else {
            log.info("OK");
        }
    }
}

在我们的应用程序中,我能做些什么来改变这种行为并使用Apache的实际版本吗?

编辑:

删除标记camel-cdijboss-weld。我创建了单元测试,以模拟这种情况,而不依赖于camel-cdi和Weld。此测试包含用于测试JndiRegistry#lookup的断言,该断言返回正确的实例。根据这个测试,我认为问题在于bean组件本身。使用版本>=2.20.0失败,并与<=2.19.5传递

代码语言:javascript
复制
public class CamelDependentTest extends CamelTestSupport {

    private Context context;
    private JndiRegistry registry;

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:in")
                        .to("bean:something?cache=false");
            }
        };
    }

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry registry = super.createRegistry();
        registry.bind("something", new SomeDependentBean());
        this.context = registry.getContext();
        this.registry = registry;
        return registry;
    }

    @Test
    public void testFreshBeanInContext() throws Exception{
        SomeDependentBean originalInstance = registry.lookup("something", SomeDependentBean.class);
        template.sendBody("direct:in",null);
        context.unbind("something");
        context.bind("something", new SomeDependentBean()); //Bind new instance to Context
        Assert.assertNotSame(registry.lookup("something"), originalInstance); //Passes, the issue is not in JndiRegistry.

        template.sendBody("direct:in",null); //fails, uses cached instance of SameDependentBean
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-08 11:05:24

根据骆驼-12610的说法,Processor应该是单例范围。这种行为是在版本2.20.0中引入的。不要实现Processor接口,而是将可调用方法注释为@Handler

取代

代码语言:javascript
复制
@Named
public class SomeDependentBean implements Processor {
    public void process(Exchange exchange) throws Exception {
    }
}

代码语言:javascript
复制
@Named
public class SomeDependentBean {
    @Handler
    public void process(Exchange exchange) throws Exception {
    }
}

如果你不能像我这样,因为它破坏了我们的应用程序扩展的行为,我已经实现了简单的组件。这个组件没有缓存,允许直接从注册表调用Processor

CdiEndpoint类

代码语言:javascript
复制
public class CdiEndpoint extends ProcessorEndpoint {
    private String beanName;

    protected CdiEndpoint(String endpointUri, Component component) {
        super(endpointUri, component);
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    @Override
    protected void onExchange(Exchange exchange) throws Exception {
        Object target = getCamelContext().getRegistry().lookupByName(beanName);
        Processor processor = getCamelContext().getTypeConverter().tryConvertTo(Processor.class, target);
        if (processor != null){
            processor.process(exchange);
        } else {
            throw new RuntimeException("CDI bean "+beanName+" not found");
        }
    }
}

CdiComponent类

代码语言:javascript
复制
public class CdiComponent extends DefaultComponent {
    @Override
    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
        CdiEndpoint endpoint = new CdiEndpoint(uri, this);
        endpoint.setBeanName(remaining);
        return endpoint;
    }
}

使用

代码语言:javascript
复制
public void configure() throws Exception {
    getContext().addComponent("cdi", new CdiComponent());
    from("direct:in")
            .to("cdi:something");
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51108913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档