I have a class JobListener that is listening to a queue using Spring Integration. Inside JobListener, i have an Autowired field Helper whose scope is defined as "prototype".
public class JobListener {
#Autowired
private Helper helper;
#ServiceActivator
public void receiveMessage(Message<String> message){
helper.processMassage(message);
}
}
Now my question is, Since the scope of Helper is defined as Protype, will i get a new instance of helper every time recieveMessage is called?
The container only creates the singleton bean JobListener once, and thus only gets one opportunity to set the properties. The container cannot provide bean JobListener with a new instance of bean Helper every time one is needed.
One solution to this problem is to use Method Injection: Lookup method injection is the ability of the container to override methods on container managed beans, to return the lookup result for another named bean in the container. To implement this solution, re-define the JobListener class as this:
public abstract class JobListener {
#ServiceActivator
public void receiveMessage(Message<String> message){
Helper helper = createHelper();
helper.processMassage(message);
}
protected abstract Helper createHelper();
}
The Spring Framework will generate a dynamic subclass of JobListener that will override the createHelper method to provide a new instance of Helper every time it is requested for.
You need to define the name of lookup-method name in the JobListener bean definition:
<bean id="helper" class="x.y.Helper" scope="prototype">
...
</bean>
<bean id="jobListener" class="x.y.JobListener">
<lookup-method name="createHelper" bean="helper"/>
</bean>
With the above configurations in place, every time you execute
Helper helper = createHelper();
it will return you a new instance of Helper.
Related
I have a Managerclass annotated with #Component
and #Scope
#Component
#Scope(value = "prototype")
public class Manager {
...
}
So I expect a new instance of the Manager bean will be created each time the bean is requested.
Then I have an Adapter class which uses this Manager bean. To use it, I have two ways of Autowire: 1. on the property or 2. on the constructor:
#Component
public class Adapter {
#Autowired
Manager m_Manager;
...
}
Or
#Component
public class Adapter {
Manager m_manager;
#Autowired
public Adapter(Manager manager) {
m_manager = manager;
}
...
}
Since the Adaptor class is a singleton bean, so both #Autowire the Manageron the property or on the constructor will only create one instance of the Manager? Meaning Managerbean is actually used as a singleton bean instead of prototype bean, right?
#Autowire behaves in the same way as ApplicationContext.getBean
It creates a prototype bean for each autowired instance. you can see that the prototype object in two singletons has a different identifier
So each singleton has its own prototype instance. It doesn't have any difference if you do it with #Autowire in the constructor or field.
Do Autowire on constructor is just more convenient way to avoid annotation duplication.
P.S. To define scope is better to use
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
If you don't have any other injection points, where you inject a Manager instance, then you will only have one instance in the application context, that's correct.
Taking as reference the post Spring #Autowired and #Qualifier
We have this example to fix the autowiring conflict :
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface.
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
That's a very good example to fix this problem.
But when I have the same problem but without those balises in the application context:
<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>
All the issues are solved by using the #Qualifier annotation, but in my case we don't use the balise that permit to use annotation.
The question is :
How can I fix this issue just using the configuration in application context, that's it, without using annotations?
I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.
How can I fix this issue just using the configuration in application
context?
You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)
<context:annotation-config/>
<beans>
<bean class="your_pkg_route.Vehicle">
<qualifier value="bike"/>
</bean>
</beans>
</context:annotation-config>
I found people talking about autowire attribute in the bean
declaration and I need more explanation about it
Using Annotation
#Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the #Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.
For example, take as reference the below code:
#Autowired
#Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}
Here, #Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.
Using xml configuration
From Pro Spring 5... Spring supports five modes for autowiring.
byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
byType: When using byType autowiring, Spring attempts to wire each of the
properties on the target bean by automatically using a bean of the same type in
ApplicationContext.
constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
default: Spring will choose between the constructor and byType modes
automatically. If your bean has a default (no-arguments) constructor, Spring uses
byType; otherwise, it uses constructor.
no: This is the default
So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: #Component versus #Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):
// xml config
<context:annotation-config/>
<beans>
// use the primary tag here too! in order to say this the primary bean
// this only works when there are only two implementations of the same interface
<bean id="bike" primary="true" class="your_pkg_route.Bike"/>
<bean id="car" class="your_pkg_route.Car"/>
<bean autowire="byName" class="your_pkg_route.VehicleService"/>
<beans>
</context:annotation-config>
// VehicleService
#Component
public class VehicleService {
private Vehicle bike; // call attribute 'bike' so it is autowired by its name
public void service() {
//...
}
}
As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.
Related posts:
Why do I not need #Autowired on #Bean methods in a Spring configuration class?
Difference between #Bean and #Autowired
PS: I have not tested any of the posted codes.
You can use #Primary instead of #Qualifier
#Primary
#Component(value="bike")
public class Bike implements Vehicle {
we use #Primary to give higher preference to a bean when there are multiple beans of the same type.
We can use #Primary directly on the beans
You can also set primary attribute in XML:
property has primary attribute:
<bean primary="true|false"/>
If a #Primary-annotated class is declared via XML, #Primary annotation metadata is ignored, and is respected instead.
What it does is pretty simple:
#Inject
private Provider<ProductService> productService;
The Product service is available through productService.get() and .get() will resolve the instance from the Spring context on each call.
But when should I use it? And where?
My main use case is pretty simple: When I get circular dependencies, the provider helps to resolve the dependency at runtime. But it looks a bit random if you throw it in just when you can't create your context caused by a circular dependency.
Are there any known patterns about the usage of Providers?
In cdi, Providers are used to inject objects of narrower scope into a more broadly-scoped bean, e.g., if a session-scoped bean needs access to a request scoped object it injects a provider and then a method, which is running in a request, calls provider.get() to obtain a local variable reference to the appropriate request-scoped object.
Given the following:
#RequestScoped
public class Bean1 {
void doSomething();
}
The following will use the Bean1 instance associated with the first request in the session to use Bean2 regardless of which request is calling Bean2.doSomething():
#SessionScoped
public class Bean2 {
#Inject Bean1 bean;
public void doSomething() {
bean.doSomething();
}
}
The following will use the instance of Bean associated with the particular request that is currently calling Bean3.doSomething() i.e. a different bean for each request:
#SessionScoped
public class Bean3 {
#Inject Provider<Bean1> bean;
public void doSomething() {
bean.get().doSomething();
}
}
This interface is equivalent to org.springframework.beans.factory.ObjectFactory<T> that is typically used to avoid BeanFactory.getBean() calls in client code when looking for prototype instances. Often used with ObjectFactoryCreatingFactoryBean to get prototypes beans sourced by the BeanFactory.
example from ObjectFactoryCreatingFactoryBean javadocs:
<beans>
<!-- Prototype bean since we have state -->
<bean id="myService" class="a.b.c.MyService" scope="prototype"/>
<bean id="myServiceFactory"
class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName"><idref local="myService"/></property>
</bean>
<bean id="clientBean" class="a.b.c.MyClientBean">
<property name="myServiceFactory" ref="myServiceFactory"/>
</bean>
</beans>
With Providers, you can use the ProviderCreatingFactoryBean instead.
Other option to solve the same problem, (using inheritance instead composition) is the
lookup method injection
I always have a question from the 1st day when I used spring. If a class has a constructor that needs two parameters, but these 2 parameters are not fixed, they are generated according to input request, every time they are different, but I need spring container to manage the class's instance, how to achieve this in spring?
For example
Class A{
A(int x,int y){//omit}
}
but x, and y are not fixed,we need to calculate x and y by our program, then we can create instance for A, in ordinary java code,like below
int x=calculate(request);
int y=calculate(request);
A a=new A(x,y);
But how to make spring manages the class A's instance creation?
Additional information: Why I need Class A is managed by spring, because A depends on some other classes which are managed by spring.
The most straightforward way to do it is to use ApplicationContext.getBean(String name, Object... args) - it can create a prototype-scoped bean passing the given arguments to its constructor. Obviosly it's not a good idea to use ApplicationContext directly in any bean that uses A.
A more elegant approach is to hide the creation of A behind a factory. That factory can use the previous approach internally, or it can obtain an instance of a bean in a regular way (Provider<A>, etc) and then call a non-public initialization method to pass that parameters (instead of passing parameters through using constructor).
Yet another apporach is to use #Configurable and load-time weaving that allows Spring to initialize objects created with new. Though it requires some extra configuration of runtime environment.
they are generated according to input request, every time they are different, but I need spring container to manage the class's instance, how to achieve this in spring?
You don't. Classes that you need to instantiate in response to user input are not meant to be managed by Spring.
Just because you are using Spring to manage some beans, does not mean that all beans/classes should be managed by Spring.
You want your Spring Bean to be defined as a prototype instead of a singleton. That way, on every new request your Spring context will create a new instance of the bean.
In Java config, it will look something like this:
#Scope("prototype") #Bean public MyBean myBean() { ... }
In xml:
<bean id="myBean" class="whatever.MyBean" scope="prototype"> ...
There are also scopes that can be tied to HTTP sessions. See:
http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html
And, as others pointed out, you will have to define a factory method for your bean:
See: Spring and passing parameters to factory-method in runtime
I'd assume that int is replaceable by some Object instance.One way to achieve this is to use Spring's FactoryBean feature to customize the initialization of your bean:
class AFactory implements o.s.b.f.FactoryBean {
private SomeObject firstParam;
private OtherObject secondParam;
public Object getObject() {
return new A(firstParam, secondParam);
}
public Class getObjectType() {
return A.class;
}
public boolean isSingleton() {
return false;
// i.e. every time #getObject() is called a new instance is created === prototype scope
}
public void setFirstParam(SomeObject firstParam){}
public void setSecondParam(OtherObject secondParam){}
}
Note that if SomeObject and OtherObject can be actually other FactorBeans that are factories for the dependencies of A, then every time there is a call to AFactory#getObject(), you'd actually receive a new instance of A that uses fresh instances of its required dependencies.
You could try to use this method in BeanFactory class (extended by ApplicationContext)
Object getBean(String name, Object... args)throws BeansException;
in your case:
context.getBean("A", x, y);
where "A" is the bean name for class A.
Maybe you have to change the constructor to:
Class A{
A(Request request){ this.x=calculate(request); ....}
}
Suppose that I have Spring service classes or JSF beans. I wire these classes in another class. There are no problems till now. I can use these injected fields in any method.
But, using them in the constructor gives me a NullPointerException.
Probably the constructor runs before dependency injection happens, and it doesn't see my injected fields. Is there any solution to use dependency injection in a constructor?
No you cannot refer to injected fields in the constructor. The framework must construct your object somehow (call a constructor) and then inject dependencies so they are empty during constructor execution. What you usually do instead is applying #PostConstruct annotation to one of your methods and perform initialization there:
class MyBean {
#Inject
private MyDependency myDep;
#PostConstruct
public void init() {
assert myDep != null;
}
}
In case of spring xml configuration you can use init-method="init" instead of #PostConstruct in your <bean> definition. Alternatively you can use constructor injection, in xml:
<bean id="myBean" class="my.package.MyBean">
<constructor-arg ref="myDependency/>
</bean>
or annotation equivalent.
Obviously, it's not possible to inject anything in an object if this object doesn't exist. And to exist, an object must be constructed.
Spring supports constructor injection:
#Autowired
public SomeService(SomeDependency dep) {
...
Spring also supports #PostConstruct, which allows initializing a bean after all the dependencies have been injected.
Don't know about JSF.