What is the difference between spring parent context and child context? - java

I was reading spring doc the core container I want to understand the purpose of ref parent when inject collaborators then I found this notion of parent context child context or parent container and current container this is the part that I'm confuse about it :
This part of doc
Specifying the target bean through the parent attribute creates a
reference to a bean that is in a parent container of the current
container. The value of the parent attribute may be the same as either
the id attribute of the target bean, or one of the values in the name
attribute of the target bean, and the target bean must be in a parent
container of the current one. You use this bean reference variant
mainly when you have a hierarchy of containers and you want to wrap an
existing bean in a parent container with a proxy that will have the
same name as the parent bean.
<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
can someone give me some help or an example of this two type of context ? and what is the purpose of the ref parent Thank you in advance

The beans of the Spring run inside an application context.
The Application Context is Spring's advanced container. Similar to
BeanFactory, it can load bean definitions, wire beans together, and
dispense beans upon request. Additionally, it adds more
enterprise-specific functionality such as the ability to resolve
textual messages from a properties file and the ability to publish
application events to interested event listeners. This container is
defined by org.springframework.context.ApplicationContext interface.
https://www.tutorialspoint.com/spring/spring_applicationcontext_container.htm
For each application context you can have many configuration files, configuration classes or a mix of both.
You can create an application context with a code like this:
ApplicationContext context = new FileSystemXmlApplicationContext("Beans.xml");
And obtain the beans with context.getBean or with #autowired.
There are some cases when you want(or need) to have a context hierarchy. In these cases Spring provides a way of specifying a parent context. If you look at this constructor, you will see that it receives a context parent.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/support/FileSystemXmlApplicationContext.html#FileSystemXmlApplicationContext-org.springframework.context.ApplicationContext-
As you can see the parent context is the same type of a child context, they both are http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html.
The difference is that they are related through a parent/child relationship. Not a compose(import) relationship.
The most common case where you see this is in a Spring MVC application, this applications have 2 context, the first is the dispatcher servlet context and the other one is the root context.
Here you can see the relationship
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-servlet
And here you can see an example of application context hierarchy in spring boot applications.
https://dzone.com/articles/spring-boot-and-application-context-hierarchy

Related

Bean with same name in Root and Child Application Context?

If I create bean with same name in Root Application context and Child Application context
(as in Root Application Context and dispatcher servlet context)
will child application context override the bean definition ?
What will be the behavior please explain ?
Also explain what will be the behavior In Java Config if I include other Configuration Class and both contain bean with same name.
Will two beans be created ? Or one will override the other.
As per my Experimentation
In the parent and child Application Context new Bean is created for each Application Context irrespective whether Bean name is same or not.
Any call made from ( autowired by ) parent application context refers to Bean in Parent Application Context.
Any call made from ( autowired by ) child application context refers to Bean in Child Application Context.
And In Java Config importing other configuration which contains bean with same name does not create a new Bean and Bean Definition is Overridden.
This effect is same as Importing bean of same name from XML.

Using global scope in spring mvc

I came across below statement from Spring MVC documentation:
Upon initialization of a DispatcherServlet, Spring MVC looks for a
file named [servlet-name]-servlet.xml in the WEB-INF directory of
your web application and creates the beans defined there, overriding
the definitions of any beans defined with the same name in the global
scope.
Please help me in understanding this statement.
As global scope is used for portlet based applications, then why a developer wants to configure like this in normal Spring MVC applications?
I don't think the term "global scope" here means the global scope bean like singleton, prototype, request, session and global. I believe the global scope here means the scope of the bean context.
In Spring MVC, there are 2 scopes of bean can be defined. The first one is at servlet context level which I believe is what it meant by "global scope" in the above statement. The second one is at servlet level where the bean defined at this level will take priority when resolved by other bean in servlet level.
The beans in servlet level will be able to resolve beans in servlet context (global) level but not the other way round.
Spring MVC provides options to configure multiple Context based on number of DispacthServlet Configuration .
For example
Consider you have two modules with in your application and url pattern starts as module1/* and module2/* . And you want to keep two different context ( always declarations in *context.xml is private to the context ). So you would be creating two dispatchServlet and provide two different servletname and url pattern. Now you have two Spring context which has specific declartions and which is not visible to other. But still you may wanted to declare some application wide beans such as persistentManager / Logger instance and so. for those case you can keep seperate config as root-context.xml and keep the generic declartions in that root. Which is considered here as "GLOBAL SESSION" Now this Global Session beans scope can be different scope based on configuration. And the bean configured in Global Session ( root-context) can be overriden by specific-servlet for customization.
I like the answer provided here also Understanding contexts in Spring MVC
A typical Spring MVC application will have two contexts: the root context and the servlet context.
The root context is loaded by the ContextLoaderListener. The ContextLoaderListener loads the ApplicationContext and sets it as an attribute in the ServletContext. This makes it available to other Servlet, Filter, and XxxListener instances.
The servlet context is another ApplicationContext loaded by the DispatcherServlet when its init() method is called. Since the init() method of a Servlet is called after the contextInitialized() method of a ServletContextListener is called, the DispatcherServlet has access to the root context set as an attribute in the ContextLoaderListener and can therefore use the beans declared there.
[...] creates the beans defined there, overriding the definitions of any
beans defined with the same name in the global scope.
A bean definition is, for example,
<bean id="someBean" class="com.company.SomeBean">
<property name="someProp" value="some value" />
</bean>
Spring creates a BeanDefinition object for this and all other <bean> declarations (or #Bean annotation methods). When the ApplicationContext is refreshed, Spring generates actual instances from these bean definitions.
What the above quote from the documentation is saying is that if you have a <bean> declaration with the same name or id in both the root context and the servlet context, the servlet context one will overwrite the root context one.

Why isn't my spring component accessible to the WebApplicationContext?

I have a spring component which was used as a flex-blazeds endpoint (using #RemotingDestination) and I now need to reuse it as a REST endpoint.
What I did was create an additional rest servlet (of type DispatcherServlet of courser) in addition to the existing blaze-ds servlet I had.
I then wanted to access the same components using REST (hence my previous question) and I found that I'm getting a 404.
My rest-servlet.xml configuration file looked something like:
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
And my ContextLoaderListener uses all my spring context files, which included the compontent-scan of those components.
Since the flex-servlet had no problem accessing these #Component beans which were scanned by the global context I assumed that the rest-servlet will also had access to them and I just need to add the annotations to the components.
The strange part was that when I explicitely added the component-scan for the package where these components reside then the rest call worked.
This meant that these component beans were being created twice, once for the global context (as it scans a config file containing this scan for the flex servlet) and one for the rest-servlet context (I verified this with a simple static counter and a lock on the class).
My question is why can't the rest-servlet see the beans the flex-servlet can?
While it's true that the servlet appcontext can access the beans from the ContextLoaderListener appcontext, those beans will not be consulted when mapping HTTP calls to controllers. All controller beans must be declared (or scanned) directly in the servlet's appcontext, else they will be ignored.
I suggest that you separate the REST entry point annotations (i.e. #RequestMapping) from your BlazeDS ones. For example, take your UserService class from your other post: create a UserController class, put the REST annotations on that, and delegate from UserController to UserService. UserController would be declared in the servlet app context, and injected with the UserService from the ContextLoaderListener context.
You need to use Spring Web context and define a DispatcherServlet, which will be a child context for the one loaded by ContextLoaderListener.
It is DistpatcherServlet that should load your rest-servlet.xml, not ContextLoaderListener. Otherwise, the guys whom you call "servlets" and who, in fact, I assume, are controllers, just won't get the requests from your client.
You can read about all this stuff here: http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/mvc.html
This is a standard way of doing Web-related things in Spring, and you definetely need to follow it.

Spring 3 Dependency Injcetion

I am using Spring3 with xml based configuration.
The problem is when the IOC container starts it loads/caches all the properties/fields defined in com.dao.MyDAOFactory class. I want to tell spring that only load/cache specific properties/fields.
The bean declaration is given below
<bean id="daoFactory" class="com.dao.MyDAOFactory" ></bean>
Can any one help me ?
You can use the lazy-init attribute to defer the loading of your beans, but eventually all of them will be loaded.
Also keep this in mind that if a non-lazy singleton bean depends on one or more lazy beans, the lazy beans will be loaded at startup.

Spring set abstract bean property value

I need to chance spring bean property values on runtime. Currently I'm doing it this way
Object bean = context.getBean(beanName);
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
wrapper.setPropertyValue(propertyName, newValue);
But some beans are configured as abstract
<bean id="abstractFoo" abstract="true" class="com.Foo" />
<bean id="bar" class="com.Bar">
<constructor-arg><bean parent="abstractFoo" /></constructor-arg>
</bean>
and in that case context.getBean("abstractFoo") throws BeanIsAbstractException
This is really simplified example, but I hope you get the idea.
Any idea how to change property value of abstract bean (in this case 'abstractFoo')?
We're using spring 2.5.4
Edit
Changed a XML example to be more specific. abstractFoo is declared abstract because of security reasons.
Spring application context contains bean definitions, and Spring instantiates bean objects defined by these definitions.
Your current code obtains an object that was created from the named bean definition, and changes its property. However, abstract beans are never instantiated as objects, they exist only in the form of definitions which are inherited by definitions of concrete beans.
So, if you want to change properties of abstract beans, you need to change their definitions, that can be done using BeanFactoryPostProcessor. Note, however, that post-processors are applied during container startup, so if you want it to be actually "runtime", you this approach is not applicable.
Disclaimer: this is untested; off the top of my head. Not sure if it will work after the init phase.
You need to get in instance of a ConfigurableListableBeanFactory. Your appcontext probably is one, so you can probably cast it.
From there, get the bean definition and change the property.
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory)context;
BeanDefinition fooDefinition = clbf.getBeanDefinition("abstractFoo");
MutablePropertyValues pv = fooDefinition.getPropertyValues();
pv.add(propertyName, newValue);
Maybe you need to re-register your beandefinition with the ConfigurableListableBeanFactory after that. I'm not 100% sure; you'll have to test that.
Keep in mind that if it works, it will only work for beans that are instantiated after the change.

Categories