New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Devtools: Same class with different classloader causing NoSuchBeanDefinitionException #3316
Comments
I have also tried with 1.3.0.BUILD-SNAPSHOT which is also causing an exception. |
Do you have a sample application we could try? Usually Spring will use the context classloader to load beans (which should be the |
Sorry @philwebb I was on vacation. I am trying to understand how this whole stuff is working. I will let you know details. |
I have found the same issue using:
To reproduce the issue, Spring HATEOAS HypermediaSupportBeanDefinitionRegistrar class is creating a DelegatingRelProvider with "_relProvider" name: BeanDefinitionBuilder delegateBuilder = BeanDefinitionBuilder.rootBeanDefinition(DelegatingRelProvider.class);
delegateBuilder.addConstructorArgValue(registryBeanDefinition);
AbstractBeanDefinition beanDefinition = delegateBuilder.getBeanDefinition();
beanDefinition.setPrimary(true);
registry.registerBeanDefinition(DELEGATING_REL_PROVIDER_BEAN_NAME, beanDefinition); But it doesn't qualify as a org.springframework.hateoas.RelProvider instance in org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration$HypermediaConfiguration$HalObjectMapperConfiguration:
Going a bit deeper, I've found the same case that @cemo. DelegatingRelProvider classloader is RestartClassLoader. Closing spring-hateoas in the IDE, or removing spring-dev-tools from classpath prevents any error. |
@sergiorc I've hit the same issue when developing devtools. It's to do with the way that the split classloader is created. Since eclipse will be exposing We have some logic in The easiest workaround for now is to disable inter-project resolution in eclipse or simply work on |
@cemo are you still having the issue? Did you have other Spring projects open in your workspace? |
I have created a sample application with our codebase with not all of our modules. This application was working properly but when I started run at production application, I am having same issue. I hope that I will give a try with latest beta and narrow issue. |
@philwebb |
It will happen indeed with any library that deserialize content. Caching libraries, in particular, are affected. |
Ok, thanks by the info |
Just to confirm it, I've experienced the same problem with spring-security oauth2 jdbc store, which serializes objects. For instance when inspecting the classloaders of my object and the class as used within the application I get those two :
Hence the classcast with my class not being able to be cast to itself. |
I really would like to help you. But I have limited knowledge on this area. I have no idea why some of my classes are loaded by But I have noticed that Please let me know for further helps. |
@cemo Thanks. Every class that's available directly on the filesystem, i.e. not packaged in a jar, should be loaded by the The different behaviour that you've observed for beans loaded via |
I am using such a pattern:
I have some additional observations:
Problem is still persist. However when I do not import and instead put whole bean logic inside XXXAutoConfiguration as this:
Problem is solved. I am still trying to reproduce with a simple application. |
I suspect this is the root of the problem. A breakpoint on |
@cemo Another thought: the stack trace when you can see an application class being loaded by |
Your comments make sense since I have loaded Now I am trying to run a scenario where some of my configuration inside a library class. I will try to investigate such a scenario: Project A: Has a I will let you know. |
I have just reproduced issue :) In 5 minutes I will upload. |
In order to reproduce: I have 3 project:
In order to reproduce:
You will see that there is same class Here is the project link: |
Thank you. I am 99% certain that this is a variant of #3805. The problem is that Library B, as it's in a JAR, is loaded by the app class loader. This means that any application classes that it loads, i.e. those that should be loaded by the restart class loader are loaded by the app class loader instead. We have a fix in mind for #3805 that @philwebb has prototyped. Based on the discussion I had with him this morning, I'm hopeful that it'll fix this issue too. |
I agree with Andy that this is a variant of #3805 but I don't think that the fix for #3805 will fix it. Devtools works by creating a split classloader, the idea being that the application classes are in a loader that is thrown away and library classes are in the one that's kept. Usually this works fine because library classes (like Spring/Jackson etc) have no direct dependencies on your user defined classes. The problem in your example is that "B" has a dependency on "A" but has ended up in the lower classloader because it's not unpacked:
What we need to do is find a way to pull 'B' up into the restart classloader. Perhaps we could do this with some system property, or perhaps we could try to do it automatically perhaps based on package names. |
Ah, crap. It's essentially the same problem as Orika has (#3697). |
@philwebb What do you think about putting a file inside each necessary jar by either maven or gradle plugins to support reloading by restart classloader? |
@cemo It's tricky because that only works if you are responsible for generating those JARs. In the Orika case, it's someone else's JAR. Is there any specific reason why in your case Library B can't be imported into your IDE? |
Actually we have dozens Library B's which are infrastructure codes. Our codebase can be considered into two parts. A highly reusable components of infrastructure codes and our websites which are available for end users. Our websites are maintained by junior developers and I do not want to confuse their minds. Their primary goals are using libraries, many of them are working in a declarative manner, in an efficient way. Our infrastructure codes are versioned whereas websites are working less restrictive way. Importing all infrastructure codes requires checking out necessary git tags etc... This process is not easy and require additional steps even in github to authenticate users to pull necessary projects. In contrast to this process, current situation is quite lightweight. They just need to declare a dependency and all the magic happens thanks to you and our glue codes. Another solution might be changing logic inside bean comparison in Spring Core. The root cause is actually having same class with different classloaders. I am not sure how this idea sounds but have you ever considered to change in Spring Core to check equality by only their fully qualified name? I am currently not aware of implications of this decision but just make you sure that you have considered it. |
Allow `META-INF/spring-devtools.properties` files to be used by application developers to declare is specific jars should be included or excluded from the RestartClassLoader. A typical example where this might be used is a company that develops it's own set of internal JARs that are used by developers but not usually imported into their IDE. See gh-3316
I've added support for |
I can confirm that this issue is fixed. Thanks for your efforts. PS: Don't forget removing |
I'm having trouble to setup |
@gaeloberson That should be the right place. Try putting a breakpoint on |
For anyone hitting this issue with Drools, I found this config worked for me:
|
added spring-boot-autoremote added jitpack repository for grabbing spring-boot-autoremote dependencies added MIT license added spring boot devtools workaround for issue #3316 spring-projects/spring-boot#3316
@philwebb I have started to check our applications and came across an issue. (Sorry if It is already fixed)
Short description: My applications can not find some of beans when application starts.
Detailed description: I have debugged and found that If a class is loaded with two different class loader, the
java.lang.Class#isAssignableFrom
seems can not handle correctly. This is causing a problem inorg.springframework.util.ClassUtils#isAssignable
which is used for bean comparison. As a result a bean not found exception is raised.I have checked each class and noticed that classes are loaded by
AppClassLoader
andRestartClassLoader
.This bean is registered by
@Import
configuration class. Spring Framework is registering beans withAppClassLoader
but classes of other beans are loaded byRestartClassLoader
.The text was updated successfully, but these errors were encountered: