pf4j-spring icon indicating copy to clipboard operation
pf4j-spring copied to clipboard

Handle Scope annotation on extension class

Open decebals opened this issue 7 years ago • 4 comments

decebals avatar Dec 06 '17 17:12 decebals

From log:

2017-12-06 19:25:05,724 DEBUG org.pf4j.AbstractExtensionFinder -    org.pf4j.demo.hello.HelloPlugin$HelloGreeting
2017-12-06 19:25:05,724 DEBUG org.pf4j.spring.ExtensionsInjector - Register extension 'org.pf4j.demo.WhazzupGreeting' as bean
2017-12-06 19:25:05,735 INFO org.pf4j.spring.ExtensionsInjector - Registering org.pf4j.demo.WhazzupGreeting with scope: prototype
2017-12-06 19:25:05,738 DEBUG org.pf4j.spring.ExtensionsInjector - Registering extensions of the plugin 'welcome-plugin' as beans
2017-12-06 19:25:05,738 DEBUG org.pf4j.spring.ExtensionsInjector - Register extension 'org.pf4j.demo.welcome.WelcomePlugin$WelcomeGreeting' as bean
2017-12-06 19:25:05,739 INFO org.pf4j.spring.ExtensionsInjector - Registering org.pf4j.demo.welcome.WelcomePlugin$WelcomeGreeting as singleton
2017-12-06 19:25:05,739 DEBUG org.pf4j.spring.ExtensionsInjector - Registering extensions of the plugin 'hello-plugin' as beans
2017-12-06 19:25:05,739 DEBUG org.pf4j.spring.ExtensionsInjector - Register extension 'org.pf4j.demo.hello.HelloPlugin$HelloGreeting' as bean
2017-12-06 19:25:05,740 INFO org.pf4j.spring.ExtensionsInjector - Registering org.pf4j.demo.hello.HelloPlugin$HelloGreeting as singleton
Found 3 extensions for extension point 'org.pf4j.demo.api.Greeting'
>>> Whazzup
>>> Welcome
>>> Hello

decebals avatar Dec 06 '17 17:12 decebals

I see a problem when we try to add scope on HelloGreeting (an extension of Greeting from HelloPlugin). HelloPlugin extends SpringPlugin, so it comes with an plugin context (application context) that contains beans that are visible only in this plugin.

@Extension(ordinal=1)
@Scope("prototype")
public static class HelloGreeting implements Greeting {

    @Autowired
    private MessageProvider messageProvider;

    @Override
    public String getGreeting() {
//        return "Hello";
       // complicate a little bit the code
       return messageProvider.getMessage();
    }

}

The exception is:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetings': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.List org.pf4j.demo.Greetings.greetings; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.pf4j.demo.hello.HelloPlugin$HelloGreeting': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.pf4j.demo.hello.MessageProvider org.pf4j.demo.hello.HelloPlugin$HelloGreeting.messageProvider; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.pf4j.demo.hello.MessageProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

The idea is that MessageProvider is a bean defined in plugin application context and we try to register bean definition HelloGreeting in the big application context, and a MessageProvider bean doesn't exists.

Of course we can something like:

if (plugin.getPlugin() instanceof SpringPlugin) {
    ApplicationContext pluginContext = ((SpringPlugin) plugin.getPlugin()).getApplicationContext();
    beanDefinitionRegistry = (BeanDefinitionRegistry) pluginContext.getAutowireCapableBeanFactory();
}
registerExtension(extensionFactory.create(extensionClass), beanDefinitionRegistry);

in ExtensionsInjector, but the bean will be registered in plugin context and will not be visible from the big application context, from this reason HelloGreeting will not be in the list with extensions for Greeting.

Now, when we use register as singleton, the problem discussed above doesn't appear.

It's clear that we can play with an application context hierarchy in Spring but I don't know how. The context child can see the beans from context parent but the context parent doesn't see the beans from the context child.

decebals avatar Dec 06 '17 21:12 decebals

This is useful, release it please~

goto100 avatar Aug 08 '18 12:08 goto100

@goto100 After I reread my last/previous comment, I see that is a problem in some scenario and from this reason probably I didn't merge this PR to master. I don't use Spring in my projects (but I used in the past) and from this reason I don't have some internal information about Spring. I think that pf4j-spring project needs some help from the Spring people to move things forward.

decebals avatar Aug 08 '18 15:08 decebals