Notify the Spring bean to be re-created - java

We have a problem where we need to force a spring session bean to be recreated with the initial configurations specified in configuration xml file.
And all autowired dependencies should point to newly created bean. Is that possible to do anyhow with Spring framework? Or could you suggest any method to do this?

I would suggest to create another temporary bean in your context, and use it in your conditional case. unfortunately, I will have to call getBean() method to reassign my reference to the temp bean.
For example:
In your configuration file, you will have to define two beans:
<bean id="originalBean" class="x.y.z.MyBean" />
<bean id="temporaryBean" class="x.y.z.MyBean" />
And in your beans that reference that bean you will have to autowire using the #Qualifer
#Autowired
#Qualifier("originalBean")
private MyBean myBean;
And in your conditional use case you will reassign that reference to the temporaryBean
if(conditioalCase) {
myBean = ApplicationContext.getBean("temporaryBean");
}

Related

Loading a Map in field of Class Object, before the Class instance is returned by getBean method of Spring?

I have a .properties file having 10 key-values pairs say age =10, name=Jon etc. I have configured a bean in spring which has a map as a member variable.
When the bean is loaded by Spring once I call the getBean method, before that the Map should be loaded with the properties from files. How to do that ?
I know this should be done in one of the lifecycle methods like afterPropertiesSet using InitializingBean or init-method configuration. Is there any other better way to do this ?
You can enable annotations in your beans:
<context:annotation-config />
Then you can define method with #PostConstruct annotation. Spring will execute it during bean initialization process:
class MyBean {
private Map<String, String> properties;
#PostConstruct
public void initialize() {
// read properties and initialize map
}
}
Another option is to inject Properties directly into your bean and provide map-like API to access them:
<util:properties id="myProperties" location="classpath:my-props.properties">
<bean id="myBean" class="com.example.MyBean">
<property name="properties" ref="myProperties" />
</bean>
you can use context property-placeholder within XML spring configuration file using ${...} or from java class configuration file using #value.

ways to inject a object of a class in spring controller?

I need to inject a object of a java class in spring controller through applicaionContext.xml. My controller will be ,
#Controller
public class SpringController{
private MyClass obj;
}
I know I can do it with #Autowired annotation.
Is this really good to create a object for a controller through applicaionContext.xml ? Also can I inject a object of a class in controller using the <property> tag inside a <bean> tag ?
Is this really possible ? or please forgive me if it is a stupid question.
I need to know the possible ways for how to inject a object of a class in Spring controller ?
You can of course use #Autowired annotation to autowire the relationships, which can reduce the need to define the properties and constructor arguments for the controller in your applicationContext.xml file. And also to add a dependency to a class, you don't need to modify the configuration files.
But it has some disadvantages too, like if you use #Autowired, there will not be any explicit documentation for the wiring details between Spring managed beans. And to know the relationships between the beans, you have to go through your managed beans. But, if you use configuration files to define the relationships, the relationship details can be found in one place.
You can inject an object of a class into your controller through your applicaionContext.xml as below:
Constructor based injection:
#Controller
public class SpringController{
private MyClass obj;
public SpringController(MyClass obj){
this.obj=obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<constructor-arg ref="myClassImpl"></constructor-arg>
</bean>
Setter based injection:
#Controller
public class SpringController{
private MyClass obj;
public void setObj(MyClass obj){
this.obj=obj;
}
public MyClass getObj(){
return obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<property name="obj" ref="myClassImpl"></property>
</bean>
If you want to inject an object in a controller and you particularly want to you use xml,then instead of component scanning of Controller you should create a bean of the controller class of singleton scope in the application context.
Your controller class need not be annotated with #Controller.
you then have to you extend some Controller also like AbstractCommandController, AbstractController, AbstractFormController, AbstractWizardFormController, BaseCommandController, CancellableFormController, MultiActionController SimpleFormController, UrlFilenameViewController
Now to inject a particular object you can use Either Constructor and Setter based injection.
or you can use Autowring by name or type to auto inject the object.
Make sure that you have also declared the bean of that object also in Application Context.
After a DispatcherServlet has received a request and has done its work to resolve locales, themes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView.
Thats it.
Actually, injection with xml and annotation is same behind the scene. Xml is old fashion while annotations are newer.
Basically, there are 2 types of injection types.
byName
Autowiring by property name. Spring container looks at the properties
of the beans on which autowire attribute is set to byName in the XML
configuration file. It then tries to match and wire its properties
with the beans defined by the same names in the configuration file.
You can give explicit names to beans both with xml and annotation.
#Service("BeanName")
#Component("BeanName")
#Controller("BeanName")
<bean name="BeanName" class="someclass"></bean>
and inject beans by using #Qualifier annotation.
#Autowired
#Qualifier("BeanName")
and with xml
<bean id="MyBean2" class="MyBean2 class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
byType
Autowiring by property datatype. Spring container looks at the
properties of the beans on which autowire attribute is set to byType
in the XML configuration file. It then tries to match and wire a
property if its type matches with exactly one of the beans name in
configuration file. If more than one such beans exists, a fatal
exception is thrown.
Default auto wiring mode is byType, so spring will look for matching type in auto wiring. However, older versions of Spring has default behavior none on injection. If you want to inject byType using xml, you should tell spring contaioner explicitly.
For example MyBean2 has a reference to MyBean, by setting autowired attribute to byType it handles injection automatically.
<bean id="MyBean" class="MyBean class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
<bean id="MyBean2" class="MyBean2 class"
autowire="byType">
</bean>
It also depends on where the injection take place in your code. There are 2 types, setter getter injection and constructor injection.
Note : There is no difference in #Controller since they are already in spring context.
See also
Spring Beans Auto wiring
I ran into such problem. I was getting "Ambiguous mapping found". (I use xml configuration as well and i am injecting a bean into my controller)
Then looking at my console i realized that my controller was being instantiated twice.
In more detailed look i noticed that my annotation
#Controller(value = "aController")
(Note value = "aController")
was different from my xml configuration where i was instatiating the same controller with different bean id
<bean id="aControleRRRRR" class="package.ControllerClassName"
p:property-ref="beanToInject" />
(Note id="aControleRRRRR")
So in conclusion your #Controller name (value = "aController") needs to be exactly the same as the name you give in the XML configuration (id="aControleRRRRR"), so that Spring can manage to distinct that they refer to the same bean (instance)
Hope this helps

Spring: How to make class a bean if one constructor-arg is a ref bean but another is not?

I have a class
public class MakeMeBean {
#Autowired private IAmBean var1;
private IAmNOTBean var2;
public MakeMeBean() {}
public MakeMeBean(IAmNOTBean var) {
this.var2 = var;
}
}
I want to make this class as a bean so I make a wireup.xml as
<bean id="make-me-bean" class="com.blah.blah.MakeMeBean">
<constructor-arg index="0" ref=<PUT REFERENCE BEAN HERE>
<constructor-arg index="1" <I don't want to put anything>
</bean>
Question
a.) How can I make a bean in which one instance variable is a bean and another not? I don't want to inject var2(another bean in wireup.xml)
b.) <PUT REFERENCE BEAN HERE> is a bean imported from jar file, how can I make reference to this bean in wireup.xml
You can't just have some beans in context that you created and another half that spring created (at least not that simple), if you want to manage the instances over spring, spring should have the objects on its context. Of course you have the possibility to instantiate the objects in the context, and after the instantiation you could invoke some setters to set some properties.
In order to use another to user another bean, that I suppose comes from another Spring context, the other spring context needs to be imported in the first one. In order to import a context file you can use:
<import resource="resourcePath" />

Ability to create bean template in Spring

Lets say I have a situation like this:
<bean id="sample" class="ComlicatedClass" scope="prototype">
<property name="someProperty" value="${propertyValue}"/>
</bean>
I want to be able to create the bean programatically and provide value for propertyValue at runtime (pseudocode ahead):
appContext.getBean("sample", "propertyValue" => "value")
In a way, I want to create "bean template" rather than full defined bean. Is that possible in any way in spring?
EDIT:
The value for propertyValue is known at runtime! There is no way to define it as another bean.
why don't you just do
Sample sample = appContext.getBean("sample");
sample.setSomeProperty(appContext.getBean("someOtherBean"));
Have you looked at the Prototype scope?
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container. As a rule, use the prototype scope for all stateful beans and the singleton scope for stateless beans.
There is also the #Scope annotation if you are using the Java based container configuration.

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