I would like to auto-wire foo:
#Autowired
Foo foo
but I cannot modify class Foo and mark it as #Component. What is the cleanest way to autowire foo?
BTW, I would prefer to use Java Spring configuration instead of XML config if you need to use config to address this problem.
Related:
Understanding Spring #Autowired usage
The #Bean annotation seems to be what you're after...
In your Javaconfig class you would create an #Bean annotated method returning Foo:
#Bean
public Foo foo() {
return new Foo();
}
See: http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
You can use an xml configuration file to create a bean of the class Foo. Then #Autowired works the same as annotating the beans directions.
Sample xml file:
<beans>
<bean id="foo" class="Foo"/>
</beans>
If you now include this into your file with the autoscan then this bean is used as if it were annotated with #Component.
Related
What is the programatic equivalane to defining a bean like this in xml:
<bean id="foo" class="com.bizz.Foo" />
Ideally I would like to be able to have spring create that bean, without using XML and without calling new and for this to happen within a #Configuration type class. For example:
#Configuration
public ConfigBar {
#Bean
public com.bizz.Foo foo() {
return /* Programmatic equivalent of <bean id="foo" class="com.bizz.Foo" /> here*/;
}
}
I don't think new Foo() is equivalent:
as spring is able to pick which constructor to use which may not be the no args constructor.
and spring is able to inject dependencies, which I don't think will be done here.
I know that spring is doing some reflection to achieve this, however simply stating that is not the answer to this question.
so how can we let spring create the Foo bean programmatically letting spring inject dependencies, pick the constructor and perhaps other tasks that spring would normally do when defined in XML?
The equivalent is #Component or any variant thereof such as #Controller or #Service. So long as your bean is in a package included in the component scan Spring will be able to find your bean at runtime and inject it into other beans.
As an example:
#Component
public class Foo {
//...
}
#Service
public class Bar {
// Spring will find and inject Foo bean creating it if necessary when
// creating the Bar "service" bean
#Autowired
private Foo foo;
//...
}
I have worked it out:
#Bean
#Autowired
public Foo foo(AutowireCapableBeanFactory autowireCapableBeanFactory) {
return autowireCapableBeanFactory.createBean(Foo.class);
}
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.
I have a Spring Configuration class that looks like:
#Configuration
public class MyDependencyConfig {
#Bean
#Primary
public MyDependency getMyDependency(){
System.out.println("getMyDependency");
return Mockito.mock(MyDependency.class);
}
#Bean
public MyDependency getMyDependency2(){
System.out.println("getMyDependency2");
return Mockito.mock(MyDependency.class);
}
}
And have elsewhere in my code:
#Autowired
MyDependency foo
Why is it when the application context starts up, my console prints
getMyDependency
getMyDependency2
when only the bean from getMyDependency() will be used? I am using spring boot-1.5.1.RELEASE
Thank you kindly,
Jason
The Spring configuration instantiates and loads all declared and required beans in the Spring container at the startup of the Spring context.
So, even if you don't use all beans defined in your configuration, the methods annotated #Bean in your configuration will be all invoked.
The #Primary annotation has another goal.
It indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency. If
exactly one 'primary' bean exists among the candidates, it will be the
autowired value.
It is just a way to not specify systematically the #Qualifier annotation when you have more than one candidate bean.
For example in your case as one of two beans is specified as primary :
#Bean
#Primary
public MyDependency getMyDependency(){
System.out.println("getMyDependency");
return Mockito.mock(MyDependency.class);
}
You don't need to specify the qualifier "getMyDependency" to inject which one specified as primary :
#Autowired
#Qualifier("getMyDependency")
MyDependency foo;
You can directly do that :
#Autowired
MyDependency foo;
While for the second one bean that is not specified as #Primary :
#Bean
public MyDependency getMyDependency2(){
System.out.println("getMyDependency2");
return Mockito.mock(MyDependency.class);
}
You have to specify #Qualifier to clear ambiguities when you want to inject it :
#Autowired
#Qualifier("getMyDependency2")
MyDependency foo;
Loading beans in a lazy way is not advised as it delays the catch of configuration errors. So, it is eager by default.
You have more details in the link provided in your comment.
Now, if you want to prevent this default behavior and define a lazy initialization for a bean, you can alternatively specify the lazy String value in the #Scope annotation of the bean :
#Bean
#Scope("lazy")
public MyDependency getMyDependency(){
...
}
or better you can annotate the bean declaration or all the configuration (if you want that all beans be lazy initialized) with a #Lazy annotation.
For a specific bean :
#Bean
#Lazy
public MyDependency getMyDependency(){
...
}
For all beans of the configuration :
#Lazy
#Configuration
public class MyDependencyConfig {
...
}
It seems not the case. I used to have the notion that XML configurations are meant to override annotations. But when I set autowire="no" in the XML configuration, the bean's #Autowired annotated property still takes effect. I'm no longer sure if XML autowire has anything to do with #Autowired anymore. It's quite counter-intuitive in my opinion.
Can someone point me to a documentation that says something about this?
Here's my example:
<bean class="com.example.Tester"></bean>
<bean class="com.example.ClassToTest" autowire="no"></bean>
public class Tester
{
#Autowired
ClassToTest testSubject;
}
public class ClassToTest
{
#Autowired // I want this not to get autowired without removing this annotation
private OtherDependency;
}
autowire="no" means we have to explicit wire our dependencies using either XML-based configuration or #Autowire and it is default setting.
Auto-wiring by xml configutaion or by annotation means implicitly mapping dependencies using given strategy.
For more details refer here
I have two implementations of interface IFoo: Foo1 and Foo2.
I need the context to be able to inject the correct one for any class that wants an IFoo without that class knowing what implementation it's going to get (so no use of #Qualifier).
Example of usage:
class Bar {
#Autowired IFoo foo;
}
I have a FactoryBean<IFoo> class that has the logic for which one to return.
The issue is that I also want to have those two impls go through the IOC because they have dependencies themselves.
public class FooFactory implements FactoryBean<Foo> {
#Autowired Foo1 foo1;
#Autowired Foo2 foo2;
#Override
public IFoo getObject() throws Exception {
if(someLogic()){
return foo1;
}
return foo2;
}
}
If I autowire them into the factory I get an exception of
"No unique bean of type IFoo is defined: expected single matching bean but found 3: [fooFactory, foo1, foo2]"
Any way to tell spring to just use the default of fooFactory for everyone else but use the two implementations inside the factory?
You could use the notion of the "primary" bean. Assuming that you're using XML config, then:
<bean id="fooFactory" class="x.y.FooFactory" primary="true"/>
Now, #Autowired IFoo foo should select the result of the factory, in preference to the foo1 and foo2 beans.
I would also recommend using #Resource inside the factory itself, rather than #Autowired, i.e.
public class FooFactory implements FactoryBean<Foo> {
#Resource Foo1 foo1;
#Resource Foo2 foo2;
This reduces the chance of the autowiring chasing its own tail, since #Resource will inject a specific, named bean (i.e. foo1 and foo2). You'd still use #Autowired in Bar.
If you use #Resource like that, then an alternative to use primary="true" is to exclude the foo1 and foo2 beans from autowiring, e.g.
<bean id="foo1" class="x.y.Foo1" autowire-candidate="false"/>
You can inject a list:
#Resource
private List<IFoo> foos;
Unfortunately it might not work since you are currently constructing FooFactory, so you might get circular dependency error. Try it!
But the more idiomatic wat since Spring 3.1 would be to use #Profile or #Configuration:
#Bean
public IFoo foo() {
if(someCondition) {
return new Foo1(dep1(), dep2());
else
return new Foo1(dep3(), dep4());
}
Where dep...() methods are also #Bean declarations.
You can trz to annotate the factorys result wiht #Primary.
I have not tryed it, and have no IDE here to test it, but may it works.
#Configuration
public class MyFactory {
#Bean
#Primary
public IFoo getFoo () {
...
}
}
Take a look at bean factory scopes.
related post on stackoverflow
Spring Bean scopes