Kotlyarov Pavel opened SPR-15605 and commented

I currently implementing plugin architecture for my application. It will consist of such modules: core (contain API and part of domain, available for modules), platform (contain implementations for interfaces from core and main part of application) and plugins (contains additional functionality for extension points). Core will be loaded by parent classloader and all other modules will be loaded by different children classloaders to avoid dependency hell problem. And all of this i planned to union in single context at application initialization time by this way:

new AnnotationConfigApplicationContext(CoreContextPart.class, PlatformContextPart.class, PluginAContextPart.class, PluginBContextPart.class);

But i encounter a problem. Looks like Spring suggest that in such scenarios developer will use children Spring contexts for plugins. But it makes lifecycle of application much more complicated and i can't autowire main application services in plugins (they live in sibling classloaders and thats why in sibling spring contexts). Some time ago i already succesfully implement such solution with Guice. But when i tried it with Spring i understood that it has strange limitation - all beans from context loads by only one classloader. And thats why if this is the root classloader of my application it doesn't see classes from my plugins and platform.


Affects: 5.0 RC1

Comment From: spring-projects-issues

Juergen Hoeller commented

This is an intentional design decision and simplifies many assumptions in the framework, in particular towards proxy creation. After all, it is rather unusual for a single larger context to be sourced from several class loaders. Decomposition into one application context per class loader, like in an OSGi environment, is indeed what we recommend here.

That said, where specifically does it fail for you? You're configuring your context with pre-resolved classes, so I suppose it might indeed fail when creating some proxies?

Comment From: spring-projects-issues

Kotlyarov Pavel commented

OSGi is huge, complicated programming platform, that increace complexity of application and need a lot of efforts in learning for team and integrating into existing application. Without requirements of dynamic registration and update for plugins, it's totally redundant. And don't forget about upcoming and unavoidable Jigsaw.

From the outside it don't looks like very complicated to respect classloader of every context part. Especially for Java configurations.

Unfortunately i haven't example of fail at current time, may be some time later i will provide it. I suppose that problem is contained in Java configuration analysis with bean discovery and i don't exclude that it may be proxy creation.

Comment From: spring-projects-issues

Kotlyarov Pavel commented

Sorry for long waiting. I finally found time to make simplified example, reproducing this problem. Parts of Context, loaded by different classloaders at this time was just ignored.

https://github.com/tr1cks/springclassloaders

Comment From: spring-projects-issues

Kotlyarov Pavel commented

I fixed some bugs in my example and added third plugin with explicit bean creation. Now i get this exception:

июл 04, 2017 2:46:59 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5ce65a89: startup date [Tue Jul 04 14:46:59 YEKT 2017]; root of context hierarchy Exception in thread "main" java.lang.IllegalStateException: Cannot load configuration class: spring.plugina.PluginAContext at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:403) at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:249) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:125) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) at org.springframework.context.annotation.AnnotationConfigApplicationContext.\(AnnotationConfigApplicationContext.java:84) at spring.multipleclasspath.MultipleClasspathMain.main(MultipleClasspathMain.java:24) Caused by: java.lang.ClassNotFoundException: spring.plugina.PluginAContext at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.springframework.util.ClassUtils.forName(ClassUtils.java:250) at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:401) at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:392) ... 7 more

Comment From: spring-projects-issues

Kotlyarov Pavel commented

I added workaround for this problem https://github.com/tr1cks/springclassloaders/commit/7dadc2793bdc4c9059f257802d0176647269b901. He's not even as tricky as I thought.