I have an interface Animal having two implementations Cat and Dog. These two implementations are spring #Component. How do I conditionally wire these two based on a value? I understand that I may have to change the scope of MyTestController from singleton to request.
#RestController
public class MyTestController {
#Autowired
Animal animal;// how to wire bean of Cat or Dog based on animalName
#PostMapping("/get-animal")
public #ResponseBody Animal getAnimal(#RequestParam(value = "animalName") String animalName) {
return animal;
}
}
Since both MyTestController is a bean the autowiring / initialisation happens before you actually start using the class instance itself. What I mean is that by the time you actually trigger REST requests on your controller, the injected animal bean should be already there!
More specifically if you have two classes that implement the same interface (Animal) without further specification (active Profiles, or #Primary annotation) Spring won't be able to decide which implementation to inject while creating the MyTestController,
What you want to do is return beans from your ApplicationContext based on a parameter / class name. This would look something like this:
#Autowired
private ApplicationContext context;
/* ... */
if(animalName.equals("dog") {
context.getBean(Dog.class) //returning the dog bean
} else if(animalName.equals("cat") {
context.getBean(Cat.class) //returning the cat bean
}
Edit IMO the question is a bit confusing. You ask for wiring the bean based on a value, but this value only comes at runtime. Hence my answer. However If you want to wire based on some variable at initialisation of your bean I would suggest taking a look at the following sources:
Profiles - With profiles you can tell spring which instance to inject in which configuration. (E.g.: production/development/test configs and for each you want to inject different beans)
Primary - One of your bean takes precedence over the others while injecting it.
Qualifier
Finally I would note that such an inversion on the IoC is considered as a bad practice. (See here)
Well, you're missing the whole point. Don't autowire simple DTO, but autowire AnimalFactory or some kind of AnimalRepository (or better - Service) where you can create or retrieve animals based on animal type.
It would look something like that:
#Component
public class AnimalFactory {
public Animal createAnimal(String animalType) {
switch (animalType) {
case "DOG":
return new Dog();
case "CAT":
return new Cat();
}
throw new IllegalArgumentException("AnimalType is invalid");
}
}
Animal Spring Data JPA Repository:
#Component
public class AnimalRepository implements JpaRepository<Animal, Long> {
public Optional<Animal> findByAnimalName(String animalName);
}
Related
I can't find a simple way to inject a component/service given a runtime value.
I started reading # Spring's doc: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers
but I can't find there how to variabilize the values passed to the #Qualifier annotation.
Let's say I've got a model entity with such interface:
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
In my client code, I would do something like:
#Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
... with my service being:
#Service
public class DoService {
#Inject
// FIXME what kind of #$#& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
#Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
I expect the caseService to be the UKCaseService (see related code below).
public interface CaseService {
void modify(Case caze);
}
#Service
#Qualifier("uk")
public class UKCaseService implements CaseService {
}
#Service
#Qualifier("us")
public class USCaseService implements CaseService {
}
So how do I "fix" all of this in the most simple / elegant / efficient way by using either/all Spring feature(s), so essentially NO .properties, NO XML, only annotations.
However I already suspect something is wrong in my DoService because Spring would need to know the "case" before injecting the caseService... but how to achieve this without the client code knowing about the caseService?!
I can't figure this out...
I already read several issues here on SO, but most of the times either they don't really have the same needs and/or config as I have, or the posted answers aren't enough satisfying to me (look like they're essentially workarounds or (old) usage of (old) Spring features).
How does Spring autowire by name when more than one matching bean is found?
=> only refers to component-like classes
Dynamically defining which bean to autowire in Spring (using qualifiers)
=> really interesting but the most elaborated answer (4 votes) is... almost 3 1/2 years-old?! (July 2013)
Spring 3 - Dynamic Autowiring at runtime based on another object attribute
=> quite similar problem here, but the answer really look like a workaround rather a real design pattern (like factory)? and I don't like implementing all the code into the ServiceImpl as it's done...
Spring #Autowiring, how to use an object factory to choose implementation?
=> 2nd answer seems interestingly but its author does not expand, so altough I know (a bit) about Java Config & stuff, I'm not really sure what he's talking about...
How to inject different services at runtime based on a property with Spring without XML
=> interesting discussion, esp. the answer, but the user has properties set, which I don't have.
Also read this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references
=> I can't find expanded examples about the use of "#" in expressions. Does someone know about this?
Edit:
Found other related-to-similar issues, no one got a proper answer:
How to use #Autowired to dynamically inject implementation like a factory pattern
Spring Qualifier and property placeholder
Spring: Using #Qualifier with Property Placeholder
How to do conditional auto-wiring in Spring?
Dynamic injection in Spring
SpEL in #Qualifier refer to same bean
How to use SpEL to inject result of method call in Spring?
Factory Pattern might be a solution?
How to use #Autowired to dynamically inject implementation like a factory pattern
You can obtain your bean from the context by name dynamically using a BeanFactory:
#Service
public class Doer {
#Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
A side note. Using something like country code as bean name looks a bit odd. Add at least some prefix or better consider some other design pattern.
If you still like to have bean per country, I would suggest another approach. Introduce a registry service to get a required service by country code:
#Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
#Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Example usage:
#Service
public class DoService {
#Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
In this case you have to add String getCountryCode() method to your CaseService interface.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Alternatively, you can add method CaseService.supports(Case case) to select the service. Or, if you cannot extend the interface, you can call CaseServices.register(String, CaseService) method from some initialiser or a #Configuration class.
UPDATE: Forgot to mention, that Spring already provides a nice Plugin abstraction to reuse boilerplate code for creating PluginRegistry like this.
Example:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
#Service
#Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
#Service
#Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
#Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
#Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}
According to this SO answer, using #Qualifier isn't going to help you much: Get bean from ApplicationContext by qualifier
As for an alternative strategy:
if you are spring boot, you could use #ConditonalOnProperty or another Conditional.
a lookup service, as #aux suggests
just name your beans consistently and look them up by name at runtime.
Note that your use case also appears to revolve around the scenario where beans are created on application startup, but the bean chosen needs to be resolved after the applicationContext has finished injecting the beans.
I am currently improving my Spring knowledge. I wonder what really happens when I use Spring annotation #Autowire on a field.
Here is a piece of code :
OutputHelper file
#Component
public class OutputHelper {
#Autowired
#Qualifier("csvOutputGenerator")
private IOutputGenerator outputGenerator;
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}
// I can focus only on what my code do because my objects are injected
public void generateOutput(){
outputGenerator.generateOutput();
}
}
CsvOutputGenerator file
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput(){
System.out.println("Csv Output Generator");
}
}
Application file
public static void main(String[] args) {
// Create the spring context
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/spring-module.xml");
// Get the configured OutpuHelper from the spring-module.xml
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
// Display output from the output configured
output.generateOutput();
}
My configuration file just contain <context:component-scan base-package="com.xxx.xxx.output"/>
When I execute this code all work fine. But what makes me surprised is when I delete the setOutputGenerator in OutPutHelper file, my piece of code keeps working. I tought that with this configuration, the OutputHelper was first created with default constructor and initialized with setter.
I expected an error because the variable outputGenerator was not be able to be initialized.
Is anyone can help me to understand ?
The idea to have fields #Autowired is questionable. It works, but it will difficult other aspects of your implementation (i.e. testing).
There are 3 types of injections:
fields - basically configured applying reflection (Field.set(Object, Object)) directly to the field:
#Autowired
private MyInterface field;
setters - with this approach the configuration of each dependency goes through a property (spring goes through all methods and execute each one annotated with #Autowired using Method.invoke(Object, Object...), thus its value is configured using its setter as follows:
#Autowired
public void setField(MyInterface value) {
this.field = value;
}
constructors - the last, and my preferable approach, the constructor injection. That one basically annotates an constructor with #Autowired and instead of using methods or fields, you can configure your bean directly on your constructor. For that spring will elect the a constructor to be used to instantiate your #Component, and it will use an #Autowired if existent or a empty params constructor, invoking it using Constructor.newInstance(Object...). Example:
#Component
public class Implementation {
private MyInterface field;
#Autowired
public Implementation(MyInterface value) {
Assert.notNull(value, "value should not be null");
this.field = value;
}
}
One of the ideas behind Inversion of Control (or Dependence Injection) is to be able to isolate a piece of code in order to provide decent test implementation support.
In order to go deeper, it is necessary to comment that during a unit test you want the class in its isolated form, all you will use with that class are basically mocks for its dependencies (injections).
So, what are the results:
If you do field injection, it will be quite costly to every single time set the beans using some reflection to configure the bean during your tests (another logic needs to be introduced to configure the bean to be tested).
With setter injection approach you will be able to use your own bean to configure it with mocks necessary to isolate your implementation and test its functionality.
And finally, with the constructor injection approach you will have not only the support to configure your bean, but you will be able to require its dependencies. This means that for every new dependency a new parameter on your constructor is added, this brings you come advantages on development time, for example, you will be able to see on development time the unit tests affected with the introduction of that new dependency (once your IDE will point it out for your).
Simple answer
Actually, the setter is useless, since the CDI use java Reflection to access fields.
It means that fields are no longer accessed by method calls.
Reflection allow iterating throught all fields of a class and check if there are annoted with a specific annotation.
In this case, if a field in your class is annoted With #Autowired (or #Inject wich is more J2E complient), the container will iterate throught searching if there is a registered bean that fits the current property.
Going deeper
When you context is starting, the container iterate classes and search all field annoted with #Inject or #Autowired.
For these fields, it search an available bean.
Here is the must simple example :
public class SpringClassInChargeOfDependencyInjection {
public void handdleInjections(T objectWithInjectableField) {
Class<T> clazz = objectWithInjectableField.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Inject.class)) {
//find a bean for the type;
Object injectableBean = getAvailablebean(field.getType());
field.setAccessible(true);
//inject the value into the class, this line explain why the setter is not necessary
field.set(objectWithInjectableField, injectableBean);
}
}
}
}
This is a non-working example just to explain how it works.
Tips
You might consider using #Inject instead of #Autowired, the later was created by Spring, #Inject is a part of the the JSR-330. Spring does understand #Inject as well, you just need to add the javax.inject jar dependency to your project. If later you want to switch from spring to something else (guice for example) you won't have to change all your #Autowired annotations
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
I have recently learned concept of autowiring in spring. When I was trying to understand in which particular scenarios spring autowiring can be useful
I came up with the below two reasons from one of the questions asked in our stakoverflow forum.
1.I wanted to read values from a property file and inject them into a bean. Only way I could figure out how to do this at start up of my app was to
wire the bean in XML (and inject the properties.) I ended up using the "byName" attribute (because the bean was also marked as #Component) and then
used #Autowired #Qualifier("nameIChose") when injecting the bean into another class. It's the only bean I've written that I wire with XML.
2.I've found autowiring useful in cases where I've had a factory bean making another bean (whose implementation class name was described in a system
property,so I couldn't define the all wiring in XML). I usually prefer to make my wiring explicit though;
Can any body please give me some code snippet example of the above situations that would make my understanding of autowiring more clearer?
Here is an example of injecting properties into a bean.
Using field injection:
#Component
public class YourBean {
#Value("${your.property.name}")
private String yourProperty;
}
Using constructor injection:
#Component
public class YourBean2 {
private String yourProperty;
#Autowired
public YourBeans2(#Value("${your.property.name}") String yourProperty) {
this.yourProperty = yourProperty;
}
}
The following is a super simple example of autowiring various beans
#Component
public class Foo {
public void doSomething() {
}
}
#Component
public class Bar {
private Foo foo;
#Autowired
public Bar(Foo foo) {
this.foo = foo;
}
public void doSomethingElse() {
foo.doSomething();
}
}
In the previous example, no XML configuration of Foo and Bar needs to be done, Spring automatically picks up the beans because of their #Component annotation (assuming of course that component scanning has been enabled)
We have an interface:
public interface NotifyService {
public void send();
And a class that implements it
public class EmailNotifyService implements NotifyService {
private EmailBuilder _builder;
#Autowired
PersonRepository _personRepository;
... other Autowired Repositories ...
public EmailNotifyService(EmailBuilder builder) {
this._builder = builder;
}
public void send() {
// send mail using _builder.getRecipient().getEmailAddress(), etc.
}
We used to instantiate EmailNotifyService with a builder:
public class EmailBuilder {
private Person _recipient;
private EmailType _type;
private Event _event;
public EmailNotifyService build() {
return new EmailNotifyService(this);
}
public EmailBuilder recipient(Person recipient) {
this._recipient = recipient;
return this;
}
... and so on. But now, instead of using build() to create a new EmailNotifyService, we are trying to use Autowire with Spring instead. The problem is that everywhere else in our app, we are Autowiring interfaces, not classes. And from what I've read it's a good idea in general. In fact, I've tried rewriting the NotifyService to be an Abstract class, and then have EmailNotifyService just extend it. But Spring isn't Autowiring it correctly, it doesn't create a Proxy like it does for interfaces, and all of my Autowired fields are null.
So it would seem we're stuck with Autowiring the NotifyService interface. Fine. What I can't get my head around is - how can I get the data I used to assign with the builder -- the Person, EmailType and Event -- into a Spring Autowired interface?
I suppose I could change the interface definition to have a setPerson(), setEmailType(), etc., but apart from being really ugly, it defeats the purpose of using an interface in the first place. A different NotifyService (WebServiceNotifyService or RestNotifyService for example) night not have need for that info.
Is there any elegant, best-practice way to do this?
Thanks.
EDIT
I am using annotations, very little xml. And I am also using transaction management, which might explain why the abstract class isn't properly autowired? This is the only pertitnent info I have in xml:
<context:annotation-config />
<context:component-scan base-package="com.myco.myapp" />
<tx:annotation-driven transaction-manager="transactionManager"/>
What I mean when I say "autowiring isn't working correctly" is that when I try to autowire the abstract class, Spring doesn't seem to be creating a Proxy like it does for interfaces, and all the Autowired fields in my EmailNotifyService (PersonRepository, others ...) are null. When I use an interface, all the Autowired fields are wired correctly.
But my main problem is that I used to work explicitly with a concrete class, using a builder to create a new EmailNotifyService() directly, and pass it info -- Person, EmailType and Event. These are just normal beans. There are no setters/getters for them in EmailNotifyService but there are the EmailBuilder, which used to live inside EmailNotifyService.
But now I am using the NotifyService interface, which knows nothing about Person, EmailType or Event. But I need this info in order for EmailNotifyService to work.
So my question is, if I use Spring to Autowire my EmailNotifyService like this:
#Autowired
#Qualifier("email") // so Spring knows I want to use the EmailNotifyService implementation
NotifyService _notifyService
How can I set the Person, EmailType and Event data, since NotifyService knows nothing about them?
Currently we are using the mailer service within a web app but theoretically the mailer service should be able to work stand-alone. Regardless, I don't see how request scoped beans can help me here.
Robert what do you mean by not autowiring correctly? Are you getting any error?
Generally both interface and class auto-wiring works in Spring unless you have some autoproxy configured example #Transactional.
You do not need to have setPerson(), setEmailType(), etc. in your interface but have them autowired in the concrete class which requires them.
But seems Person is not a service but a bean which holds data and its specific to a request. If yours is a web application then look at request scope proxy to inject Person like bean.
So you are using transactions which is why class based injection is failing. Add proxy-target-class="true" to tx:annotation-driven.
Regarding your injection of Person and EmailType then you have to do that to the bean EmailNotifyService. In EmailNotifyService I do not see any Person or EmailType variables defined. Also read what I said about Person bean above.
Your design is not correct. You should not make EmailBuilder a bean and look to autowire to the EmailNotifyService. Instead in EmailNotifyService you should have a method send(EmailBuilder builder) where you pass the builder which you created somewhere dynamically.
After going thru autowiring concept
i have got some questions. These are:-
If i need to autowire below class byType or byName , is it mandatory to have setStudent() method in class College?
public class College {
private Student student1;
private String registration1;
}
<bean id="student1" class="Student"/> - in case of byname it will look into id attribute and in case of bytype it will look for class attribute in above
Stetement. Right? If incase it finds two bean dean tags for the same type it will throw fatal error in case of bytype. Correct?
autodetect Scenario chooses constructor or byType through introspection of the bean class. If a default constructor is found, the byType mode
will be applied.
My question here if default constructor is not found and constructor with argument is found then autowire by constructor
will be applied. Correct?
Do we need to specify #Autowired somewhere in College to apply the autowiring. As i can see this in this example
but nothing is specified here
1), 4) There are two separate ways of autowiring in Spring: XML-based and annotaion-based.
XML-based autowiring is activated from XML config, as described here. In the end, it will call setter method, so setStudent() method is required here.
Annonation-based autowiring, on the other hand, is performed via reflection magic. It attempts to fill everything you mark with #Autowired annotation. In fact, it can set private field with no accessors, as in
public class Foo {
#Autowired private Thingy thing; // No getThing or setThing methods
private void doStuff() {
// thing is usable here
}
}
For #Autowired annotaion to work, you will need to define corresponding bean post-processor; it is done by adding the following line to xml config:
<context:annotation-config/>
Note, that these two autowiring methods are independant, and it is possible(but not recommended) to use them simultaneously. In that case, xml autowiring will override annotations.
2) In general, autowiring will fail, if it cannot find one and only one candidate for injection. So, in your case, it will fail with exception upon container creation. There are some fallback quirks, but in general it works reliably.
3) Yes, documentaion says so.
About byName and byType autowiring. While byName autowiring simply tries to match bean name (can be specified with id attribute), byType is a bit more complex than class attribute lookup. It searches beans by type, and it will match interfaces. Example:
public interface SomeService {
void doStuff();
}
public class SomeServiceImpl implements SomeService {
#Override public void doStuff() {
// Implementation
};
}
public class ServiceUser {
#Autowired
private SomeService someService; // SomeServiceImpl instance goes here
}
P.S. You are referencing two different versions of Spring in your question, 2.5 and 3.0. Autowiring behavior is same in both.
In Addition if you are using #Autwired annotation you need to mark the classes as candidates for autowiring. It should be done by using one of these annotations:
#Repository
#Service
#Component
#Controller
and of cause you can configure it in different scopes:
#Scope("prototype")
#Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Hope it makes it more clear.