I have an exisiting Spring application in Java and I want to add a Grails web app to it and reuse the domain model and my beans from the Spring context. I already created a hibernate.cfg.xml which from what I have read should integrate the domain model. But when trying to integrate the Spring ApplicationContext, I run into the following Problem/Exception:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: A circular #Import has been detected: Illegal attempt by #Configuration class 'AppContext' to import class 'AppContext' as 'AppContext' is already present in the current import stack [ImportStack: [AppContext]]
My resources.groovy file looks like this:
beans = {
importBeans('file:grails-app/conf/spring/applicationContext-spring.xml')
}
In this xml-file, I just import my Java-config class for my Spring Java application.
I also get this circular import error when trying to define my AppContext class directly in the resources.groovy. (I assume because the code then does exactly the same.)
The error looks to me as if my AppContext is already imported by the Grais context, but when trying to use it, the beans are not present and I get the NoSuchBeanDefinitionException when trying to access them.
My question now: Does anyone know how to properly integrate my Spring context into a new Grails app?
Program version:
Java 8
Spring 4.1.0
Groovy 2.4.3
Grails 3.0.1
Gradle 2.4
Related
So I have a spring application on kotlin and to test a particular class I want to write up a script but the problem is all these classes are #Component and it'll be pain to intialize each class using new . Is there any way I can utilise the Beans configured in my main function.
I've tried setting up applciation context which returns null, tried lot of things from internet but no luck.
So, after some searching. I found a way.
in the main function where the Spring application starts.
val context = runApplication<App>(*args)
val crawler = context.getBean(MyClass::class.java)
ref: Accessing Spring managed beans outside spring managed classes in kotlin
Setup
Spring Boot 2.6.0
Spring Cloud Config 3.1 RC1
Apache Maven 3.8.x
OpenJDK 11
Overview
I have a multi-module Apache Maven project that is set up with the following modules:
bootstrap: contains a PropertySourceLocator for BootstrapConfiguration, defined in spring.factories file.
starter: depends on bootstrap, and it's a (servlet-based) web application
reference: deploys the starter application using the Maven Cargo plugin, deploying into an Apache Tomcat 9.0.55
Runtime
The starter module declares a configuration class, annotated with #PropertySource("wa.properties"). This wa.properties on the classpath of the starter module has a setting: cas.authn.syncope.name=Starter
The starter module has a ServletInitializer that sets the spring.config.name property to "wa" when building the spring application.
The reference module only has a wa-embedded.properties file on the classpath with a setting: cas.authn.syncope.name=Embedded
The reference module starts with the spring activated profiles: embedded,all
Note: the cas.authn.syncope.name is bound to a Java POJO, CasConfigurationProperties, that is annotated with #ConfigurationProperties("cas").
Observation
The following bean in the application exists, simplified for this post:
#Bean
#ConditionalOnMissingBean(name = "something")
#RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public Something something(ApplicationContext ctx, CasConfigurationProperties cas) {
...
}
If I look at the contents of cas.getAuthn().getSyncope().getName()), it shows: "Starter"
If I look at ctx.getEnvironment().getProperty("cas.authn.syncope.name"), it shows "Embedded".
In other words, property binding used during the bootstrapping process does not match the actual environment for the application's context.
Analysis
It appears that when the bootstrap application context is created, wa-embedded.properties, a profile-specific property is not read. In fact, the only property source that is used for binding is wa.properties as part of "localProperties", which I believe comes from #PropertySource("wa.properties"). Nothing else is read or found.
Then, property binding takes place binding CasConfigurationProperties and cas.authn.syncope.name initialized from #PropertySource("wa.properties"). The value of this property is set to Starter.
Then, the application servlet context is initialized and its environment is post-processed with profiles and the appropriate listener and Spring beans are created. In particular, this bean:
#Bean
#ConditionalOnMissingBean(name = "something")
#RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public Something something(ApplicationContext ctx, CasConfigurationProperties cas) {
...
}
...shows that ctx is the actual application context with an environment that is post-processed via all profiles and shows ctx.getEnvironment().getProperty("cas.authn.syncope.name") as "Embedded".
However, CasConfigurationProperties was processed using the Bootstrap context only, and its equivalent property shows "Starter".
...which means the bean would be created using the wrong values in CasConfigurationProperties.
Research
This setup works OK using Spring Boot 2.5.6 and Spring Cloud 3.0.5. I don't think anything in Spring Boot has changed that would affect this, but I do see a number of differences in Cloud between 3.0 and 3.1.
I am not sure I can create a reproducer to adequately showcase this. I'll try. In the meantime, could you evaluate this and see if this might be seen as a bug, or misconfiguration of some kind?
I have a spring boot rest service that included an external project in pom as it's dependency. That external project is basically a jar that has spring AOP code.
The base package in my main application that includes this external jar with spring AOP code is x.y.z
The class in external jar where the #before advice is, is under the package a.b.c
With this class under a.b.c package, it doesn't get recognized by the main application where I want to use the spring aop implementation and apply the aspect. However, when I change it's package from a.b.c to x.y.z (which I really can't do in real life) it works fine.
I know that in spring boot service which happens to be the including service, it scans everything under root package given in the application class, x.y.z in this case and that is why aspect works fine if it's class is under x.y.z.
however, the problem is that this spring app jar will be used across multiple applications. So changing package name like this is not an option.
Is there a way to accomplish this without changing the package name of the class where spring app code is ?
Probably component scan is only activated for your application class packages by default. You can extend it to multiple packages, including the aspect package:
XML style configuration:
<context:component-scan base-package="x.y.z, a.b.c" />
Annotation style configuration:
#ComponentScan(basePackages = {"x.y.z", "a.b.c"})
Disclaimer: I am not a Spring user, only an AspectJ expert. I just knew that you can configure component scan, googled the syntax for you and hope it is correct.
Please define the bean (of jar project )inside main application. Give the #ComponentScan(basePackages = {"x.y.z", "a.b.c"}) as well as #EnableAspectJAutoProxy. Also include below piece of code.
ex:
` #Bean
public LoggingHandler loggingHandler()
{
return new LoggingHandler();
}`
Also annotate external jar code with:
`#Aspect
#Component
public class LoggingHandler {`
What #kriegaex suggests is correct. In addition to that, please make sure you are using #Component along with #Aspect. Since #Aspect is not a Spring annotation, Spring won't recognize it and hence your aspect won't be registered. So, using #Component is mandatory to getting aspects to work in Spring environment.
I have created a spring mvc based application but I didn't use this #Configuration annotation. What is the purpose of using #Configuration annotation? By using this, what are we communicating to springMVC container?
Assuming your application is using xml configuration rather than AnnotationConfig so it is not loaded to ApplicationContext at all.
#Configuration is used when ApplicationContext has been initialized and bean registration.
#Configuration annotation is a core Spring annotation, and not Spring MVC. It is a core entry point to configuring Spring-based application using Java config instead of XML config.
Please, use Spring Documentation more often because it is a place where you will find answers to most of your questions. Like this one:
Indicates that a class declares one or more Bean #Bean methods and may
be processed by the Spring container to generate bean definitions and
service requests for those beans at runtime
In my sample spring boot application, i have added a dependency of a custom jar. My sample application has a support for web and jpa.
The jar which i've created contains a Spring MVC controller. Below is the sample code
#Controller
public class StartStopDefaultMessageListenerContainerController {
#Autowired(required=false)
private Map<String, DefaultMessageListenerContainer> messageListeners;
I haven't manually created a bean instance of this controller anywhere in my code.
Problem - When i start my spring boot application by running the main class, i get an error in console that prob while autowiring DefaultMessageListenerContainer.
My question here is, even though this class StartStopDefaultMessageListenerContainerController is just present in the classpath, it's bean shouldn't be created and autowiring should not happen. But spring boot is scanning the class automatically and then it tries to autowire the fields.
Is this the normal behavior of spring and is there anyway i can avoid this?
If the StartStopDefaultMessageListenerContainerController class is part of component scanning by spring container, Yes spring tries to instantiate and resolve all dependencies.
Here your problem is #Autowired on collection. Spring docs says,
Beans that are themselves defined as a collection or map type cannot be injected through #Autowired, because type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection or map bean by unique name.
And also Refer inject-empty-map-via-spring