I have a base plugin A based on atlassian-spring-scanner 2+ and I have additional plugins B, C, D, etc. based on atlassian-spring-scanner 2+ too.
In all of the additional plugins(B, C, D,..) I have spring @Component implemented some interface from A.
I need dynamically find those components from plugin A. How can I achieve that?
I've tried to use:
Map<String, CustomLogicProvider> beansOfType = beanFactory.getBeansOfType(CustomLogicProvider.class)
but it founds only components from plugin A. It looks like I need somehow merge OSGi classloaders from all of those plugins or something else, but I can't find a way to do that.
Hello Eduard,
You need to mark the components in your base module with @ExportAsService (or @ExportAsDevService if you only want it work in dev mode). See the code here.
After doing that the @Component annotation should allow you to import them in your other modules. You can simply auto wire them to your constructor at this point, there is no need to use getBeansOfType.
There are other annotations that can be used to optionally import components based on the product, take a look here.
Cheers
Matt
Thank you, the question is a bit about another thing. Let's imagine that my base module is already installed and I need to add other modules, where that @Component's are implemented.
And during a call to some method in base modules, It should understand what extensions(other modules) are installed and find the actual bean in them. I have an interface
CustomLogicProvider
in a base module, but it's implemented in others. And I'm trying to find all implemented beans from others by calling
getBeansOfType(CustomLogicProvider.class)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Right. I think you need ModuleTypes.
1) See the example here in the section Expose Module Types Differently via @ModuleType.
This example defines a ModuleDescriptorFactory which defines a module type that other plugins can use to implement. It also defines a ModuleDescriptor which is responsible for creating instances of your module after the plugin system reads it from the descriptor.
So, a) In your base module define a module factory that creates a module type for your logic provider.
b) define a module descriptor for the container to contain the module and logic to instantiate it from the information in the descriptor. This will be used to create the specific instances of your module in step #2.
The example in spring scanner is defining a module type "basic", you can call it what you want.
It may also be useful to read the deprecated tutorial on the module type module. Parts of this tutorial have been replaced with the approach above but gives some examples on how to implement the module descriptor.
2) In your other plugins, define a module in the plugin descriptor using the key defined by the module factory ("basic" from the example). You could pass in a class name or something as a parameter that can be used by the module descriptor to create the instance you desire.
3) You can inject a PluginAccessor in to any code in any plugin. This class has a method called getEnabledModulesByClass which can be used to find and implementations of this module.
---
There is a bit of overhead here but its abstracting away the lifecycle and management of the beans that gets really complicated when you consider installing/uninstalling and enabling/disabling plugins.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@m_ As I understand right, instances of modules will be created inside ModuleDiscriptor - it means in runtime in plugin A.
Is it possible to make module instances Spring components? How can I inject something specific to that instances? Idea is to inject some components from 3rd party services which shouldn't be in plugin A dependencies.
ModuleDiscriptor should be only one for each ModuleType, or it's possible to extend it for each sub-modules for that reasons?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've found a solution to my last question.
That code correctly finds beans, which are created by another plugin and registered as module type in atlassian-plugin.xml
@Component
public class CustomLogicDescriptor extends AbstractModuleDescriptor<CustomLogicProvider> {
@Autowired
public CustomLogicDescriptor(@ComponentImport ModuleFactory moduleFactory) {
super(moduleFactory);
}
@Override
public CustomLogicProvider getModule() {
return moduleFactory.createModule(this.moduleClassName, this);
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I just want to add that, using this method, `pluginAccessor.getEnabledModulesByClass()` should be used. `listableBeanfactory.getBeansOfType(CustomLogicProvider.class)` won't return the beans. Thank you very for posting your resolution, Eduard, it helped!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.