grails / grails-core

The Grails Web Application Framework
http://grails.org
Apache License 2.0
2.78k stars 950 forks source link

Grails 4.0.3 does not auto create Spring Cloud beans #11587

Open sjrd218 opened 4 years ago

sjrd218 commented 4 years ago

Description

I created a Grails 4.0.3 app and integrated Spring Cloud libraries so that I can pull my config from Consul. When I add the bootstrap.yml I get configuration errors on bootstrap. It appears that beans that Spring should be auto-creating are not being created and bean injections fail.

Steps to Reproduce

  1. Create an empty grails 4 app
  2. Add dependencies to Spring Cloud Consul libraries
  3. Configure bootstrap.yml to pull config from Consul
  4. Try to bootstrap and see the bean injection failures

Expected Behaviour

I expect my app to bootstrap and pull my config from Consul.

Actual Behaviour

Bootstrap fails with Spring reporting that it can't find the beans that should be auto-created.

Workaround

If I manually specify the beans in my resources.groovy file the app will bootstrap. This is not ideal and is not the behavior I would expect.

Environment Information

Example Application

https://github.com/sjrd218/ConsulCfgApp

davydotcom commented 4 years ago

Per the documentation it seems an annotation needs added to your Application.groovy Was this performed?

@EnableDiscoveryClient

sjrd218 commented 4 years ago

That annotation has no effect. Also, an equivalent Spring boot app functions fine without adding that annotation.

In a Grails 3.3.8 app, all you had to do was add the spring cloud discovery dependencies and a bootstrap.yml and it would all work fine.

I've noticed that In Grails 4.x there's a Micronaut application context that sits between the parent bootstrap application context and the regular spring application context. I wonder if this is somehow causing the issue, as it's the biggest change between 3.3.8 and 4.x.

davydotcom commented 4 years ago

It is possible but more likely that something is blocking the ComponentScan classpath for this library. Id try adding a ComponentScan for the relevant package prefix and see if youcan get it to load GitHub notifications@github.com wrote: “That annotation has no effect. Also, an equivalent Spring boot app functions fine without adding that annotation.

In a Grails 3.3.8 app, all you had to do was add the spring cloud discovery dependencies and a bootstrap.yml and it would all work fine.

I've noticed that In Grails 4.x there's a Micronaut application context that sits between the parent bootstrap application context and the regular spring application context. I wonder if this is somehow causing the issue, as it's the biggest change between 3.3.8 and 4.x.”

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

sjrd218 commented 4 years ago

Adding a manual @ComponentScan does not seem to have any effect either.

sjrd218 commented 3 years ago

To help debug this issue further I've included some screenshots of my debugger showing the object structure of the app contexts when it's going through the bootstrap process. It appears that the micronaut context isn't communicating with it's parent context and can't find the bean that it needs to bootstrap the app. In a normal spring boot app the bootstrap context is the parent of the main context and they freely communicate. With Grails 4 the micronaut context was introduced as the parent of the main spring context, but the Micronaut spring context doesn't appear to have the ability to communicate with it's parent so the bean lookups fail in the scenario where there's a bootstrap context, micronaut context, and main context.

This agrees with my previous experience when I wired all of this up with Grails 3.3.8 and it worked fine. Since there was no micronaut context the main context could pull beans from the bootstrap context without issue.

grails-app-ctx-1 grails-app-ctx-2

stacktrace.txt

puneetbehl commented 3 years ago

The problem is happening because of a bug in Micronaut for Spring where:

  1. The parentBeanFactory is not set for MicronautApplicationContext.
  2. The MicronautBeanFactory does not even check the parent. Check the following method implementation:
    doGetBean(String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly)

I am working on fixing the same in Micronaut for Spring.