Spring ServletContext bean (i.e. Controller) injection into ApplicationContext bean (i.e. Service, Dao) - spring

In Spring, relationship between Application Context and Servlet Context is like parent-child. Application Context is the parent here. So, beans of Servlet Context know beans of Application Context, but vise versa is not true. But if I need to do that, is there any way ?
For simplicity, if I inject an Controller into an Service class, what I need to do ? Is there any Application Context refreshing mechanism, after Servlet Context is initialized ?

Related

SpringBoot/Spring Cloud Config Client multiple application contexts (root & servlet) with RefreshScope annotated beans

I have a couple of questions regarding Spring Cloud Config in a web application.
Context
I'm working on an SpringBoot web application where I have a Root application context (parent) and a Servlet application context (child), I'm adding Spring Cloud Config capabilities to this application (of course this app connects to a Spring Cloud Config server via http).
When I annotate a bean that is registered in the Root application context with the RefreshScope annotation everything works as expected, the problems started when I tried to annotate a spring bean that is registered in the Servlet application context.
First problem: an IllegalStateException was thrown when the #RefreshScope annotated bean in the servlet application context was tried to be accessed, the following is the meaningful part of the stacktrace:
ERROR: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope name 'refresh'] with root cause
java.lang.IllegalStateException: No Scope registered for scope name 'refresh'
Solution: the error above was solved by registering the refresh scope to the Servlet application context
#Bean
public CustomScopeConfigurer servletCustomScopeConfigurer(org.springframework.cloud.context.scope.refresh.RefreshScope refreshScope) {
CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
customScopeConfigurer.addScope("refresh", refreshScope);
return customScopeConfigurer;
}
Question: Assuming that this way to model a web application is still relevant (I think it is), why I couldn't find any documentation stating that it's necessary to register the refresh scope to the servlet application context and I should register the org.springframework.cloud.context.scope.refresh.RefreshScope bean from the root application context?
Second problem: Once I had the refresh scope registered in the servlet application context the application started fine, and everything seemed to be working, however when I tried to update a property from the refreshable beans I had mixed results, when I refresh a property that would modify a bean in the root application context I could see the bean being updated, so all good, however when I update a property that would modify a bean in the servlet application context I could set the bean being refreshed but the new property value was not being reflected in the bean.
Solution: After some tests I realised that the ConfigurableEnvironment in both contexts are not the same, at some point the parent ConfigurableEnvironment is merged to the child ConfigurableEnvironment that is how beans in the servlet context get initialised correctly at startup, but when the ContextRefresher.refresh() is called by the RefreshEndpoint only the parent ConfigurableEnvironment is updated, and the child ConfigurableEnvironment is not leaving it with the old values, what I did now was to inject the parent ConfigurableEnvironment when creating the servlet application context and everything worked as expected, relevant code:
#Bean
public DispatcherServlet dispatcherServlet(ConfigurableEnvironment parentEnvironment) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(WebConfiguration.class);
applicationContext.setEnvironment(parentEnvironment);
dispatcherServlet.setApplicationContext(applicationContext);
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
return dispatcherServlet;
}
Question: Again I was surprised by the lack of documentation on the expected behaviour of a Spring application declaring parent and child application contexts, maybe I just didn't find it and it exists and is amazing. Is the approach of setting the parent ConfigurableEnvironment to the child servlet context the correct one?
In the default case where (parent ConfigurableEnvironment NOT set in the servlet context.) would be the fact that the child ConfigurableEnvironment is not refreshed if is intentional or a bug?
If you are still reading this, thanks! Answers to the questions above will be very appreciated!
Hopefully this helps other people dealing with these issues.

ApplicationContext - Need clarification

I am new to springs and have the following queries on ApplicationContext.
1.What does it mean to declare two instances of classPathXmlApplicationContext on a single beans.xml file?
2.How is a beanPostProcessor programmatically associated with a single ApplicationContext?
1.What does it mean to declare two instances of classPathXmlApplicationContext on a single beans.xml file?
This would result in two different Spring application context unaware of each other. If there are any beans that are defined as singleton, each application context will now have its own instances of singleton beans, which means two bean instances one for each application context.
2.How is a beanPostProcessor programmatically associated with a single ApplicationContext?
To register a BeanPostProcessor you can add that to the spring configuration(xml/annotation) as a normal bean and spring will detect that automatically during the container startup and will invoke its callback methods during bean creation.
If you want to do this programatically, you can use BeanFactoryPostProcessor and addBeanPostProcessor method

Java Spring bean scopes: singleton vs application

Could anyone explain the difference between these two Spring bean scopes?
I'm familiar with the Singleton pattern.
Would this be the only difference?
You can have a list of beans in the Spring container using application scope.
Also, are you able to run multiple web servers in one Spring container? If yes, that would be a reason to use the application scope over the singleton scope since otherwise the bean would get shared over the two servers.
The documentation explains it:
This is somewhat similar to a Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per Spring 'ApplicationContext' (or which there may be several in any given web application), and it is actually exposed and therefore visible as a ServletContext attribute
In application scope, the container creates one instance per web application runtime.
The application scope is almost similar to singleton scope. So, the difference is
Application scoped bean is singleton per ServletContext however singleton scoped bean is singleton per ApplicationContext. It means that there can be multiple application contexts for single application.
SINGLETON SCOPED BEAN
//load the spring configuration file
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("context.xml");
// retrieve bean from spring container
MyBean myBean = context.getBean("myBean", MyBean.class);
MyBean myBean2 = context.getBean("myBean", MyBean.class);
// myBean == myBean2 - output is true.

Spring - what's a bean and what's not?

I'm new to Spring and I'm confused about something basic. Are the classes that are stereotyped (Service, Controller, Repository) treated as beans? I'm confused as to when you actually need to annotate/configure something as a bean and when you don't. Is it for the classes that aren't stereotyped?
Thanks!
From spring documentation:
In Spring, the objects that form the backbone of your application and
that are managed by the Spring IoC container are called beans. A bean
is an object that is instantiated, assembled, and otherwise managed by
a Spring IoC container. Otherwise, a bean is simply one of many
objects in your application. Beans, and the dependencies among them,
are reflected in the configuration metadata used by a container.
Service, Controller, Repository are managed by the Spring IoC container, so they are called beans. You annotate a class as #Serivice, #Controller, #Repository, or more in general #Component when you want spring to manage it: spring will manage the instance of annotated class in regard of the scope you select (not all these scope are always available):
singleton – Return a single bean instance per Spring IoC container
prototype – Return a new bean instance each time when requested
request – Return a single bean instance per HTTP request
session – Return a single bean instance per HTTP session
globalSession – Return a single bean instance per global HTTP
session

Access Dispatcher servlet without accessing Application Context

I'm creating a simple Spring MVC app with a DAO layer. Now I want to access the Spring JdbcTemplate beans that I've initialized in the dispatcher servlet. I've been using FileSystemXmlApplicationContext to get to my dispatcher servlet till now, but I realized its not a good practice for MVC app when I need to deploy it elsewhere.
Can somebody let me know if I can use XmlWebApplicationContext or ClassPathXmlApplicationContext to get hold of the dispatcher servlet config file which resides in the WEB-INF folder?
I don't want to extend any ApplicationAware interface and I've also not got access to servlet context, as I'm using ModelAttribute annotations to get the data from beans in JSPs. Also, I don't have any applicationContext.xml in my web-app.

Resources