如何使用CDI构建插件架构 - 我正在使用Wildfly 10 [英] How to build a plugin architecture using CDI - I'm using Wildfly 10

查看:200
本文介绍了如何使用CDI构建插件架构 - 我正在使用Wildfly 10的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想构建一个基于JEE插件的架构。主要的想法是做类似于eclipse的东西,但是在JEE的背景下。
我的目标是以最少的模块为核心,并允许其他模块扩展其功能。
为此,我使用了4个模块实现了测试:

I want to build a JEE plugin based architecture. The main idea is do something similar to what eclipse is, but in the context of JEE. My goal is to have a minimum of modules as the core, and allow others modules extend its functionality. To this, I have implemented a test using 4 modules:

gauges: Defines and implements a gaugesregistry service, also defines a gauge POJO.
cashgauges: implements a gauge producer using CDI. this is a plugin mock.
othergauges: implements a gauge producer using CDI. this is a second plugin mock.
gauges-web: Contains a basic JSF view to query the gauges registry.

依赖关系如下:

cashgauges --> gauges
othergauges --> gauges
gauges-web --> gauges

这是通过使用 jboss-deployment-structure.xml

部署是作为单个文件完成的:

The deployment is done as individual files:

gauges.jar 
cashgauges.jar 
othergauges.jar 
gauges-web.war

所有服务都开始了,但我看到的是,我的 gaugesregistry 被多次实例化。我在调试模式下启动了wildfly,我看到每个模块都有自己的gaugesregistry实例:cashgauges和othergauges在注册表上调用相同的方法( addGauge ),但是这个注册表的实例不一样。

All services start, but what I see is, my gaugesregistry is instantiated several times. I started wildfly in debug mode and what I see is each module has its own instance of gaugesregistry: cashgauges and othergauges call same method (addGauge) on registry, but instances of this registry are not the same.

在这两种情况下都会发生这种情况,使用 @ApplicationScoped @单身人士注释。我做错了什么?

This happens in both cases, using @ApplicationScoped and @Singleton annotations. What am I doing wrong?

源代码可在上找到https://github.com/hatit/research

几天后,我正在考虑使用ServiceLocator模式和远程引用而不是CDI 。有什么建议吗?

After a couple of days, I'm considering using a ServiceLocator pattern and remote references instead of CDI. Any suggestions?

推荐答案

太棒了,我得到了两次-2票(-4点声),因为我问过软件开发人员的高级主题?

Great, i got twice -2 votes (-4 reputation) because i asked an advanced topic for software developers?

我搜索了一下stackoverflow,发现了这个

I searched in about stackoverflow and found this


成立于2008年,Stack溢出是最大,最值得信赖的在线社区,供开发人员学习,分享知识,建立自己的职业......

Founded in 2008, Stack Overflow is the largest, most trusted online community for developers to learn, share their knowledge, and build their careers...

如果有的话那么对这个主题感兴趣:

If any interested in this topic, then:

在用作独立模块(JBoss模块)后,了解CDI Beans和EJB生命周期之间的差异几个小时后,我发现:

After some hours understanding differences between CDI Beans and EJBs lifecycle when used as independent modules (JBoss Modules), i found:

Singleton CDI Beans每个模块实例化一次,而不是所有模块中的单独实例。

Singleton CDI Beans are instantiated one time per module, not really singleton among all modules.

为了避免这种情况,我必须创建注册表作为Singleton企业会话Bean。
这带来了新的问题,CDI注入在模块之间不起作用,所以我不得不打包一个CDI生产者(我不在乎它是否是单身,它只是一个生产者),它可以被任何实例化模块。这个生产者的主要职责是查找Registry EJB,这样可以避免每次需要访问Registry时硬编码jndi路径。

To avoid this i had to create Registry as a Singleton Enterprise Session Bean. This cames with new problems, CDI injection doesn't works among modules, so i had to package a CDI producer (i don't care if it's singleton or not, its only a producer) which can be instantiated by any module. Main responsibility of this producer is to lookup Registry EJB, this to avoid hardcoding jndi path each time i need access the Registry.

我改变了我的简单示例以支持JSF插件,这是我目前使用的一个例子。

I changed my trivial example to support JSF plugins also, this is an example of what i am using currently.

模块facelets:

Module facelets:

注册表界面:

public interface FaceletsModuleRegistry {
    void registerModule(String module);

    List<String> getRegisteredModules();
}

注册表实施:

@Local(FaceletsModuleRegistry.class)
@Singleton(name="FaceletsModuleRegistry")
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@Vetoed
public class FaceletsModuleRegistryImpl implements FaceletsModuleRegistry {

    private Set<String> registeredModuleNames = new TreeSet<>();

    @Override
    public void registerModule(String module) {
        registeredModuleNames.add(module);
    }

    @Override
    public List<String> getRegisteredModules() {
        return Collections.unmodifiableList(new ArrayList<>(registeredModuleNames));
    }

}

注册管理机构制作人:

@ApplicationScoped
public class FaceletsModuleRegistryBuilder {

    @EJB(lookup="java:global/facelets/FaceletsModuleRegistry!co.hatit.enterprise.facelets.services.FaceletsModuleRegistry")
    protected FaceletsModuleRegistry faceletsModuleRegistry;

    @Produces
    public FaceletsModuleRegistry getFaceletsModuleRegistry(){
        return faceletsModuleRegistry;
    }
}

我想插件的任何其他模块都会实现此代码(请参阅 @Inject 可用于任何需要访问Registry单例实例的模块):

Any other module that i want to plugin implements this code (please see @Inject can be used on any module requiring access the Registry singleton instance):

@ApplicationScoped
public class InmueblesActivator {

    @Inject
    private FaceletsModuleRegistry faceletsModuleRegistry;

    public void init(@Observes @Initialized(ApplicationScoped.class) Object init){
        String moduleName = Module.getCallerModule().getIdentifier().getName();
        String name = StringUtils.substringBetween(moduleName, "deployment.", ".jar");
        faceletsModuleRegistry.registerModule(name);
    }

}

然后我可以从任何地方引用注册表模块作为一个真正的单例实例(解决了我的问题,当在几个模块中使用CDI单例bean时,有多个相同类的实例)。

Then i can reference Registry from any module as a really singleton instance (solved my problem having multiple instances of same class when used CDI singleton beans among several modules).

现在,我可以插入JEE模块,而不是只是java代码,但facelets资源也是:

Now, i can plugin JEE modules, not just java code, but facelets resources also:

public class FaceletsResourceHandler extends ResourceHandlerWrapper {

    Logger logger = LoggerFactory.getLogger(FaceletsResourceHandler.class);

    @Inject
    FaceletsModuleRegistry faceletsModuleRegistry;

    private ResourceHandler wrapped;

    public FaceletsResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ViewResource createViewResource(FacesContext context, final String name) {
        ViewResource resource = super.createViewResource(context, name);

        if (resource == null) {
            resource = new ViewResource() {
                @Override
                public URL getURL() {
                    try {
                        //iterates over plugins to find the required resource.
                        for(String module : faceletsModuleRegistry.getRegisteredModules()){
                            URL resource = Module.getCallerModule().getModuleLoader()
                                    .loadModule(ModuleIdentifier.create("deployment." + module + ".jar"))
                                    .getExportedResource("META-INF/resources" + name);
                            if (resource != null) return resource;
                        }
                    } catch (ModuleLoadException e) {
                        throw new FacesException(e);
                    }

                    return null;
                }
            };
        }

        return resource;
    }

    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }

}

这篇关于如何使用CDI构建插件架构 - 我正在使用Wildfly 10的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆