Ability to create bean template in Spring - java

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.

Related

Enforce initialization of Spring Bean which's reference is not explicitly used

Is there a way to enforce the initialization of a Spring Bean in cases that the reference of the bean is never explicitly used or even requested in the ApplicationContext?
<bean class="foo.bar.FooBar>
<property name="fooBar" ref="foo.bar.reference"/>
</bean>
This bean is meant to do things inside, get's properties passed by IoC but it is never used by any other bean which implies that the it's reference is nowhere else configured.
My problem is, that this bean seems not to be initialized because of that.
I tried <bean .. lazy-init="false"/> but this did not do the trick.
How can ensure the bean is going to be initialized?
Since I cannot modify the application context, I would need a way doing it just in the XML configuration.
I'm not sure, but maybe you could try to use the singleton=true property for that bean - in non-singleton mode, the bean would be instatiated only if requested by the application.
http://docs.spring.io/spring/docs/1.2.9/reference/beans.html
(see 3.2.5)
Edit: Can you add some logging to ctor to see if it's called? If not, could you add an init-method and log something there?

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

ref vs depends-on attributes in Spring

I am confused between ref and depends-on attribute in Spring.I read the spring doc but I am still confused.I wish to know the exact difference between the two and in which case which one shall be used.
From the official documentation: http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/context/annotation/DependsOn.html
Beans on which the current bean depends. Any beans specified are guaranteed to be created by the container before this bean. Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialisation.
Perhaps an example of a situation where depends-on is needed would help. I use Spring to load and wire my beans. Here is an example bean definition:
<bean id="myBean" class="my.package.Class">
<property name="destination" value="bean:otherBeanId?method=doSomething"/>
</bean>
<bean id="otherBeanId" class="my.package.OtherClass"/>
Notice that the property value is a string, which references otherBeanId. Because of the way this variable is resolved, Spring doesn't learn of the dependency, so it may destroy otherBeanId then myBean. This may leave myBean in a broken state for a little while.
I can use depends on to fix this problem as follows:
<bean id="myBean" class="my.package.Class" depends-on="otherBeanId">
<property name="destination" value="bean:otherBeanId?method=doSomething"/>
</bean>
There might be a situation where a bean might be a property in another bean i.e; the property bean is directly involved in the bean definition as a property in such case we refer the beans with ref attribute.
There might be a situation where in a bean instantiation is required for the other bean to be successfully created, the other bean is not a property of the bean under definition, in such case we make use of the depends-on attribute.

Spring Injection & Globally initialized objects

I have a spring injected service
class A{
List l = new ArrayList();
public m1(){
//do some additions in list
}
public m2(){
//do some new additions in list
}
}
Now because creating of objects of A, is in the hands of spring the behavior of program is not what is expected. (I expect list to be available empty always but not initialized by methods for some wired reason)
Will Spring always create only one instance of A, so that list l will keep on growing, I have configured bean as singleton in application context.
If yes, naturally I must initialize the list inside the functions m1 & m2 or callee must past the reference, and in my case callee being struts2 actions they are not singleton so this issue can be solved?
Or
Does spring provide any support in configuration to initialize member variables at every call or something else?
More generally what are best practices to have in writing services injected by spring about using member variables/ local variables for performance & efficiency.
Trying to answer following :
Does spring provide any support in configuration to initialize member variables at every call or something else?
By default Spring beans are singleton. Initialized only once and use the same object again and again.
However, if requirement changes as you asked. You need to understand scope attribute provided by the Spring.
<bean id="id" class="com.test.TP" scope="prototype">
</bean>
Refer following for detail understanding.
Scope Description
singleton
Scopes a single bean definition to a single object instance per
Spring IoC container.
prototype
Scopes a single bean definition to any number of object instances.
request
Scopes a single bean definition to the lifecycle of a single HTTP
request; that is each and every HTTP request will have its own
instance of a bean created off the back of a single bean definition.
Only valid in the context of a web-aware Spring ApplicationContext.
session
Scopes a single bean definition to the lifecycle of a HTTP Session.
Only valid in the context of a web-aware Spring ApplicationContext.
global session
Scopes a single bean definition to the lifecycle of a global HTTP
Session. Typically only valid when used in a portlet context. Only
valid in the context of a web-aware Spring ApplicationContext.
http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s04.html
It is also possible to have user defined scope such as thread scope.
You can configure your bean as follows:-
<bean id = "serviceBeanA" class = "somepkg.A" scope="prototype">
<property name = "l">
<value>
<list>
<value>ABC</value>
.....
</list>
</value>
</property>
</bean>
I'm not sure if I understand the question but your sample class should work fine with spring. Spring will call the default constructor unless you pass in constructor args in the configuration file. As long as you have an id="..." in the bean then it will create a singleton of that class. Then, the first class that calls a.m1() will see l as being an empty list.
What may be happening is that you have multiple instances of A being created. See here about Spring singletons versus non. To quote:
Beans are defined to be deployed in one of two modes: singleton or non-singleton. (The latter is also called a prototype, although the term is used loosely as it doesn't quite fit). When a bean is a singleton, only one shared instance of the bean will be managed and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned.
So if you don't have an id or name specified in your Spring configuration then you might get multiple instances of A created.
The non-singleton, prototype mode of a bean deployment results in the creation of a new bean instance every time a request for that specific bean is done. This is ideal for situations where for example each user needs an independent user object or something similar.

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