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
Upgrade to Spring Boot 1.5.14 and 2.0.3 #7783
Comments
Brussels-SR11 expected tomorrow! |
For Spring Boot 2.0.3 the build is currently failing, it looks like they changed the way Ehcache is configured, I'm on it. |
I tried to update a 4.x app to 1.5.14 this morning and had also problems with the cache configuration. Somehow it seems the order has changed again as it fails because ehcache is configured after datasource again. Works with 1.5.13 and applying your fix from this commit: 843a671 |
Oh and my trainees also had this problem recently - what is happening here, this is making everything fails :-( |
Nope @atomfrede - this is probably something close, but the fix doesn't work for me... In fact I have 2 caches, one created before (the correct one, with our setup), and then another one. It looks like Hibernate doesn't see the existing Ehcache instance and creates a second one. |
So for Spring Boot 2.0.3 this fails because we use our own io.github.jhipster.config.jcache.NoDefaultJCacheRegionFactory for the Hibernate The idea is that if you don't configure your cache for each entity, it won't be cached. So our class is a hack that makes the app crash if those caches are not configured correctly, which I find is a good idea. Then that class is kind of a hack, and for some reason it doesn't work anymore. I still find the idea very good, then it's also a bit against our Policy 1 - even if in that case the default config is pretty stupid (making you think your class is cached, when it is not...). I'll have a closer look, but otherwise let's just remove this. |
This is so buggy...
That's a really bad default configuration from Spring Boot! So let's not do this, and I'm stuck again :-( |
I think this part was coded by @henri-tremblay - Henri, does that ring a bell to you? |
A quick summary as I don't know if I'll have more time on this today. With this new Spring Boot 2.0.3 release:
So:
Any help here would be greatly appreciated! |
And I think its the same for 1.5.14 at least thats what I can see in the logs (without investigating any further) |
Hi. Just waked up :-) I will have a look today. |
Thanks @henri-tremblay !! Indeed that's supposed to be a singleton, but caches are initialized twice, here are my logs if I use a
-> the first In that configuration, the second caches are used, so it looks like it's working, but it's not using the caches that we have configured in I'm sorry but I won't have much time this week-end on this, and this is of course very important, so help is really, really welcome. |
Ok. And where are you testing it? To you have a branch or a test project I can try? Only the Spring-boot version was changed? Not the hibernate one for instance? |
I'm using the master branch from "jhipster/jhipster" and do a "mvn clean install" so I have version 2.0.12 in my local Maven repo. |
So. The problem is there because Spring and Hibernate are no longer using the same class loader to find their |
Ok. Here is the spring-cache code that broke everything: spring-projects/spring-boot/pull/13338. However, the fix seems good so the problem is now to pass the right classloader to hibernate. @snicoll You never experienced this in one of your samples? |
Here are two solutions. They are not pretty but they work. Due to the fact that Hibernate can't take a Spring bean as a region factory, I don't see what else I can do unless something is modified in Hibernate or Spring (not sure what though). Solution 1: Just guess the class loader by taking the one of the public class ClassLoaderFixJCacheRegionFactory extends NoDefaultJCacheRegionFactory {
@Override
protected CacheManager getCacheManager(Properties properties) {
CachingProvider cachingProvider = getCachingProvider( properties );
String cacheManagerUri = getProp( properties, CONFIG_URI );
ClassLoader classLoader = getClass().getClassLoader();
URI uri = getUri(cachingProvider, cacheManagerUri);
return cachingProvider.getCacheManager(uri, classLoader);
}
private URI getUri(CachingProvider cachingProvider, String cacheManagerUri) {
URI uri;
if (cacheManagerUri != null) {
try {
uri = new URI(cacheManagerUri);
}
catch (URISyntaxException e) {
throw new CacheException("Couldn't create URI from " + cacheManagerUri, e);
}
}
else {
uri = cachingProvider.getDefaultURI();
}
return uri;
}
} Solution 2: Take the real spring class loader and hide it in a static variable. public class BeanClassLoaderAwareJCacheRegionFactory extends NoDefaultJCacheRegionFactory {
private static volatile ClassLoader classLoader;
@Override
protected CacheManager getCacheManager(Properties properties) {
Objects.requireNonNull(classLoader, "Please configure this class as a Spring Bean to get a class loader correctly");
CachingProvider cachingProvider = getCachingProvider( properties );
String cacheManagerUri = getProp( properties, CONFIG_URI );
URI uri = getUri(cachingProvider, cacheManagerUri);
CacheManager cacheManager = cachingProvider.getCacheManager(uri, classLoader);
// To prevent some class loader memory leak this might cause
setBeanClassLoader(null);
return cacheManager;
}
private URI getUri(CachingProvider cachingProvider, String cacheManagerUri) {
URI uri;
if (cacheManagerUri != null) {
try {
uri = new URI(cacheManagerUri);
}
catch (URISyntaxException e) {
throw new CacheException("Couldn't create URI from " + cacheManagerUri, e);
}
}
else {
uri = cachingProvider.getDefaultURI();
}
return uri;
}
public static void setBeanClassLoader(ClassLoader classLoader) {
BeanClassLoaderAwareJCacheRegionFactory.classLoader = classLoader;
}
} The second solution is uglier but will always work. |
Thank you so much for the analysis! I'll have a look on Sunday (no computer ATM and this needs testing). |
Yes. But this is for a little while. So it causes issues only if you are crazy enough to have a factory in a class loader common to two wars that are deployed at the same moment. The alternative is to use a thread local and assume Spring is always loaded in a single thread. |
If you have a sample that shows how it breaks, I am happy to revisit the code.
We don't have support for 2nd level cache in Spring Boot and, as far as I understand, this is why you're having this issue. I'd be happy to include such support in Spring Boot itself but never had the time to look at it (PR welcome). IMO, the code that was changed is better than the previous version. I might change my mind looking at the specifics though. |
Thanks, @snicoll. Yes. It's not a Spring issue. Using this class loader make sense. The real problem is a mix of JSR 107 playing with class loaders and Hibernate factory that can't be injected from a Spring bean. @jdubois A stupid solution could be to remove second level caching from Hibernate by arguing that the Spring cache layer should be enough. |
I'm quite happy that JHipster provides Hibernate 2nd level cache on top of Spring Boot :-) For the record, for the last month, for all JHipster generated projects:
|
Concerning the solutions: @henri-tremblay I guess solution 2 is better, as you said it will always work. It will be hidden in our library, so it's not too bad if the code isn't perfect. We'll probably also need this for Spring Boot 1.4, so I'll backport it there. I'm testing this! |
@henri-tremblay solution 1 in fact doesn't work with my setup - I don't understand why... -> if you have the time, could you do a PR? That way you would still be the author of the code, and that would prove that it works (through Travis) |
I much prefer solution 2. And I think it is easier to convert into a PR to Spring. Right now I was injecting it as a bean in CacheConfiguration. But yes, I will do a PR. |
Yes you are right @henri-tremblay ! About solution 1, I found my issue: I was putting the class into the jhipster/jhipster lib, so it wasn't in the right classloader. I had to move my class into the project, so it has to be generated by jhipster/generator-jhipster, and that's indeed awful. So I'd much prefer solution 2, if it can be put inside jhipster/jhipster, but that looks a bit hard to do. I'll also try to do it. |
@henri-tremblay got it... It's not even a Spring Bean... Really ugly code, but very easy to use from the user's point of view, and no risk to fail. I'll commit this and let you tell me what you think of it. |
…heRegionFactory to use the correct Spring classloader with Ehcache See #7783
For the record, a modified version of solution 2 was commited in jhipster/jhipster at jhipster/jhipster@662096a |
@jdubois but for the 4.x branch there shouldn't be any React test config in Travis right as its a different branch? |
can this ticket be closed? |
@deepu105 not sure what happens with Travis, but I don't think this is very important as the v4 branch is in maintenance mode now. And I'll close the ticket as soon as I finish a couple of tests. |
For the record, I think the final solution will be to configure Hibernate programmatically. I will look into it but if someone is an expert, I'm all ears. |
For the record, I think the best solution would be to configure Hibernate programmatically and inject a RegionFactory that is Spring aware. I'll have a look but if some Hibernate+Spring wants to, I'm all ears. |
@henri-tremblay I am working in a PR to migrate to spring-boot 2.1.0.x (M1 for now, but probably M2 next week). Since the current implementation in jhipster project is not complaint anymore, I would like to confirm with you what should be the new solution to avoid spontaneous cache creation? See: https://github.com/DanielFran/jhipster/tree/spring-boot-2.1.0 Thanks |
@DanielFran I will have a look this week. |
So. We can remove the It means that public class BeanClassLoaderAwareJCacheRegionFactory extends JCacheRegionFactory {
private static volatile ClassLoader classLoader;
/**
* This method must be called from a Spring Bean to get the classloader.
* For example: BeanClassLoaderAwareJCacheRegionFactory.setBeanClassLoader(this.getClass().getClassLoader());
*
* @param classLoader The Spring classloader
*/
public static void setBeanClassLoader(ClassLoader classLoader) {
BeanClassLoaderAwareJCacheRegionFactory.classLoader = classLoader;
}
@Override
protected ClassLoader getClassLoader(CachingProvider cachingProvider) {
return Objects.requireNonNull(classLoader,
"Please set Spring's classloader in the setBeanClassLoader method before using this class in Hibernate");
}
} I can PR on master if it is now appropriate. Also, that said, it should actually be possible to get rid of |
Hi @henri-tremblay. Thanks for your feedback. I commited my changes in jhipster/jhipster#88 and included your suggestion. Do you want I remove it and you PR yourself those changes? |
No that's all right. I will survive not being the committer :-) I think EXCEPTION_MESSAGE could be package scope instead of public. I wasn't aware of the LogbackRecorder which is pretty handy. Cool! |
Thanks for all your comments, I made the changes. |
@jdubois @henri-tremblay Maybe the issue with the Cache 'order' will be fixed in next release: see spring-projects/spring-boot#14181 |
@henri-tremblay @DanielFran I also add a try this morning on our
I don't know what the issue is here, but @henri-tremblay you seem to understand this very well, so help is really welcome. And if you want contributor access that can also be easily solved, if you want to be a "core dev team" member. |
For reference, this is the changes applied: jhipster/jhipster@bf25417 |
Ok. I'll try to have a look today. This comes from changes discussed with Hibernate team. I need to put it back in my head and it shouldn't be too hard to fix. |
@jdubois I tried |
@henri-tremblay This is normal, no version of jhipster-bom has been released from spring-boot 2.1.0 branch. You can download specific spring-boot jhipster project and compile it: https://github.com/jhipster/jhipster/tree/spring-boot_2.1.0 |
Ok. I was looking at the wrong jhipster-dependencies project. Now it's better. However, jhipster-framework is currently failing. |
You probably had a corrupted download, can you delete it in your Maven cache? |
Ok. Don't worry about it. I fixed it. Not sure if it's an actual issue or my Maven repository that was unhappy. |
@jdubois Have you dropped support for yarn? |
No but we changed the default, it's NPM by default now |
But |
@henri-tremblay : you can add the flag like this: |
Ok. The problem comes from a "bug" in Meanwhile, I will find a fix. |
Here is a quick fix. However, I'm looking at how to simplify a bit to get rid of |
Important CVE are fixed: https://spring.io/blog/2018/06/14/spring-project-vulnerability-reports-published
For JHipster 4 we will need to wait for the new Spring Platform BOM (should be Brussels-SR11) but it's not available yet on http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.spring.platform%22%20AND%20a%3A%22platform-bom%22
The text was updated successfully, but these errors were encountered: