Spring behaviour when using interface name also as a bean name? - java

I found the following unorthodox configuration in my code base the other day and it made me wonder. What is the expected Spring Context behavior when I use an interface name also as the name of a bean? Would it make a difference if I was using #Autowiring in my Controller? The following snippet illustrates this setup:
interface MyAppService {...}
class InfrastructureService implements MyAppService {...}
class AdministrationService implements MyAppService {...}
class InfrastructureController {
// some code
public void setMyAppService(MyAppService svc){...}
}
<bean id="myAppService" class="InfrastructureService"/>
<bean id="administrationService" class="AdministrationService"/>
<bean id="infrastructureController" class="InfrastructureController">
<property name="myAppService" ref="myAppService"/>
</bean>
Alternatively, what would be the expected behaviour if only the controller was defined as:
class InfrastructureController {
#Autowired
public void setMyAppService(MyAppService svc){...}
}

Why should it matter here? You reference beans by id in the xml, not by interface type.
<property name="myAppService" ref="myAppService"/>
This means that the property named myAppService will have the bean with id myAppService injected. Nothing about interfaces.
Edit: If you use autowiring with annotations and you have many different implementations of the same interface registered as components, then you have to use qualifiers to tell Spring which implementation you gonna use. If you have only one implementation registered, no action is needed.

If you put #AutoWired alone it search dependency by Type (In your case it is MyAppService).If you want to narrow down dependecy seaching you can use #Qualifier as below :
class InfrastructureController {
#Autowired
#Qualifier("NAME_OF_BEAN")
public void setMyAppService(MyAppService svc){...}
}

Related

Autowiring conflict in spring core with the xml configuration

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.

How to create bean using #Bean in spring boot for abstract class

I have requirement to migrate old style spring project to Spring boot.
Assume below code snippet I have to migrate to Spring boot style.
Here my ask , how to convert below abstract bean to #Bean ?
<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
<property name="sample1" ref="sample1" />
<property name="sample2" ref="sample2" />
</bean>
Write your abstract base class in plain Java (without any Spring coupling) :
public abstract class AbstractClass{
private Sample1 sample1;
private Sample2 sample2;
public AbstractClass(Sample1 sample1, Sample1 sample2){
this.sample1 = sample1;
this.sample2 = sample2;
}
...
}
Note that adding a constructor with parameters (both for the abstract class and the concrete class) makes injection easier and dependencies clearer.
Then you have two ways :
1) Annotate the concrete class(es) with #Component.
Such as :
#Component
public class MyClass extends AbstractClass{
public MyClass (Sample1 sample1, Sample1 sample2){
super(sample1, sample2);
}
}
This first way has the advantage to be short : just an annotation to add.
But it makes de facto the subclass as a bean that may potentially be loaded by the Spring context.
2) Alternatively, declare the bean in a Configuration class.
Such as :
#Configuration
public class MyConfig{
#Bean
public MyClass myClass(Sample1 sample1, Sample1 sample2){
return new MyClass(sample1, sample1);
}
}
This second way is more verbose but has the advantage to not modify the subclass code and also let clients of the class to decide whether the class should be a bean.
Each approach has its advantages and its drawbacks.
So to use according to the concrete requirement.
There is no need in converting this code. You only need to make the classes that extend com.test.core.common.AbstractClass declared as spring managed beans by either annotating them with #Component or #Service or declaring a method annotated with #Bean in your configuration class.
Generally "abstract bean" is not needed in Java Configuration, there is even no equivalent. It was needed in xml configuration for parameter inheritance which is now achievable with plain java methods. Find example from Stephane Nicoll who is Spring Core developer.
Since Java has it's own mechanism of abstract classes and inheritance in place, you don't need to do the coupling of following code in your spring coupling.
<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
<property name="sample1" ref="sample1" />
<property name="sample2" ref="sample2" />
</bean>
In XML config, you needed to do this to specify the template for inheritance of child beans. But since Springboot uses Java configuration, this part is handled directly with Java inheritance.
What it means is that you can declare this abstract class as a normal Java abstract class and treat only the child classes as beans without worrying about the abstract parent class.
When we want to instantiate an abstract class or an interface as a #Bean (with spring-java-config), we can generally:
Instantiate an anonymous inner class.
Override all abstract methods! ;(
So for a Method injection, it would look like:
#Configuration
class FreakyConfig {
#Bean
#RequestScope // !! (stateful)
public MyFooBarDelegate delegate() {
return MyFooBarDelegate.of(...);
}
#Bean // singleton, stateless, abstract (no spring deps.)! ;)
public MyFooBarAbstractSingletonBean() {
return new MyFooBarAbstractSingletonBean() { // anonymous inner class!
#Override
protected MyFooBarDelegate fooBarDelegate() { // ...and override the (injected)/prescribed methods.
return delegate();
}
};
}
} // (stress) tested ;)
Another good(?) question: Where is that latest ("current") "spring-javaconfig/docs"???
see also:
1.4.6. Method Injection
Method Injection Article
1.5.3. Singleton Beans with Prototype-bean Dependencies

How to avoid Spring configuring bean in Java config

In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory bean.

#Component with parent?

Is there any way to use <bean parent="someParent"> with #Component annotation (creating spring beans using annotation)?
I would like to create spring bean that has "spring parent" using #Component annotation.
is it possible?
Following my comment, this piece of XML
<bean id="base" abstract="true">
<property name="foo" ref="bar"/>
</bean>
<bean class="Wallace" parent="base"/>
<bean class="Gromit" parent="base"/>
is more or less eqivalent to this code (note that I created artificial Base class since abstract beans in Spring don't need a class):
public abstract class Base {
#Autowired
protected Foo foo;
}
#Component
public class Wallace extends Base {}
#Component
public class Gromit extends Base {}
Wallace and Gromit now have access to common Foo property. Also you can override it, e.g. in #PostConstruct.
BTW I really liked parent feature in XML which allowed to keep beans DRY, but Java approach seems even cleaner.
Just came across the same Construct.. (a general abstract parent Class which used Beans - with context.xml-declaration for an potential Implementation that was injected by Component-scan)
This is what I could have done in the #Component Class:
#Autowired
public void setBeanUsedInParent(BeanUsedInParent bean) {
super.setBeanUsedInParent(bean);
}
..what I ended up doing (better, since it makes clear that the injection works on the object not on classes) - and if you are able to modify the parent Class:
// abstract getter in parent Class
public abstract BeanUsedInParent getBeanUsedInParent();
..leave the actual Beans as well as their injection up to the actual implementation (the #Component Class):
#Autowired
private BeanUsedInParent beanUsedInParent;
#Override
public BeanUsedInParent getBeanUsedInParent() {
return this.beanUsedInParent;
}

Is there a way in Spring to autowire all dependencies of a given type?

I'm using annotations-based wiring (ie #Configurable(autowire=Autowire.BY_TYPE)) for a given class, and I'd like to wire all beans of a given type into it as a list:
application context:
<beans>
<bean class="com.my.class.FirstConfigurer"/>
<bean class="com.my.class.SecondConfigurer"/>
</beans>
class to autowire into:
#Configurable(autowire=Autowire.BY_TYPE) public class Target {
...
public void setConfigurers(List<Configurer> configurers) { ... }
}
All dependencies implement a common interface called Configurer
Is there a way to make this work to have all dependencies of a type wired together in a collection and injected where necessary, or should I define a <list> in XML or something?
Yes,
#Inject
private List<Configurer> configurers;
works, and you get a list of all beans implementing the interface. (multiple variations - #Inject or #Autowired, field, setter or constructor injection - all work)
This should work:
#Configurable(autowire=Autowire.BY_TYPE)
public class Target {
#Autowired
public void setConfigurers(List<Configurer> configurers) { ... }
}
This is described in section 3.9.2 of the Spring manual:
It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type [...] The same applies for typed collections.

Categories