How to build a plugin architecture using CDI - I'm using Wildfly 10

99封情书 提交于 2019-12-13 03:47:58

问题


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.

dependencies are as follows:

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

This is done by using jboss-deployment-structure.xml on each deployed file.

The deployment is done as individual files:

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

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.

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

Source code is available on https://github.com/hatit/research

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


回答1:


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

I searched in about stackoverflow and found this

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:

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

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

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.

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

Module facelets:

Registry interface:

public interface FaceletsModuleRegistry {
    void registerModule(String module);

    List<String> getRegisteredModules();
}

Registry implementation:

@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));
    }

}

Registry producer:

@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;
    }
}

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);
    }

}

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

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

}


来源:https://stackoverflow.com/questions/49096953/how-to-build-a-plugin-architecture-using-cdi-im-using-wildfly-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!