I have two controllers (ControllerA and ControllerB)
Both controllers call to a service (MyService).
MyService calls to an interface called MyRepository which has two implementations (FirstRepository and SecondRepository).
How is possible to use FirstRepository when the service (MyService) is called from ControllerA and use SecondRepository when the call comes from ControllerB?
This way I can reuse MyService and which repository is used comes from Spring Configuration.
I can see two possible solutions here.
1. In you MyService class autowire both implementations with #Qualifier annotation (you can also autowire List.
Then MyService method would have a parameter saying which MyRepository implementation should be called. I would not recommend this solution.
2. Define two implementations of MyService (FirstService, SecondService). Then FirstService would autowire FirstRepository and SecondService would autowire SecondRepository (use #Qualifier annotation again. Now you can easily inject FirstService to ControllerA and SecondService to ControllerB.
But first I would think about architecture. Maybe you don't need separate controllers?
Have you checked #Primary or #Resource or #Qualifier annotations? Based on your requirement you can choose out of them.
Something similar has been discussed here.
I ended up creating two controllers and defining two #Configuration classes, one for each #Controller.
And using the #Qualifier annotations defined two sets of beans, and then in each controller let Spring know which #Qualified bean I want injected.
#RestController
#RequestMapping("/v1/inapp/purchases")
class AController(
#Qualifier("appStore") private val redeemPurchaseService: RedeemPurchaseService
) : RedeemPurchaseApiDocumentation { // More code }
And the other controller
#RestController
#RequestMapping("/v1/inapp/purchases")
class GPlayRedeemPurchaseController(
#Qualifier("gplay") private val redeemPurchaseService: RedeemPurchaseService
) : RedeemPurchaseApiDocumentation { // More code }
And two #Configuration files, one per controller.
Related
Even when we create the Beans in a Spring configuration class, I feel it is still useful to use #Component annotation on the class just to document/indicate that it's a Bean. Is it a good idea? Can there be any other issue that Spring will find the same bean defined in two different ways?
It is bad practice to create two beans from one class...
#Component
class SimpleComponent {
}
#Bean
public SimpleComponent simpleComponentBean(){
new SimpleComponent();
}
By default if we use #Component spring creates bean with name of class, but starts with small letter simpleComponent, if we use #Bean it takes method name and create bean with name simpleComponentBean and we have duplicated beans...
If we have method name the same, as component class name, spring replace one of them and we can Inject unexpected bean.
PS: intellij idea enterprise - correct indicate about all beans.
I started with generating my application using JHipster v.3.5.1.
After some time, I needed to create validator to perform some business logic validation on my entity, when it is created with POST. So I made:
#Component
public class MyValidator implements Validator
Then, I tried to inject it into my controller (annotated with #RestController), but no matter which way I tried, it always resulted in something like that:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.my.app.service.domain.MyValidator] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Ways I tried to create bean and inject it
#Autowired
private MyValidator myValidator;
#Inject
private MyValidator myValidator;
#Autowired
#Qualifier("myValidator")
private MyValidator myValidator; (with #Component("myValidator") on class)
#Inject
#Qualifier("myValidator")
private MyValidator myValidator; (with #Component("myValidator") on class)
//Below was inserted in class annotated with #Configuration
#Bean
public MyValidator myValidator() {
return new MyValidator();
}
However I tried it - it failed. I always got NoSuchBeanDefinitionException or field value was set to null.
I've also checked class location in project structure. To be 100% percent sure it's well placed, I've put it in package the with #Services, which are scanned and work well. No effect.
I know that it seems to be pretty easy task and I know this injection is possible (I've seen it done in project in my work), but somehow I'm not able to make it work in my project.
Maybe I'm missing something in configuration? Thanks for any help :)
I believe your issue is that when you use #Autowired inside a class annotated with #Configuration you are just referencing to a bean that is defined in a separate configuration file, that is it has to be declared in another file also with the #Configuration annotation.
If you want to refer refer to another implicit bean such as your validator annotated with #Component you will need to do it in another implicit bean also annotated to with implicit notation such as #Component, #Service, #Controller, etc
The #Autowired alone should work unless you have more than one class implementing the same interface. That is when you will need to use the #Qualifier.
Motivation
As a follow-up to my previous questions on classloading
How is the Classloader for a class chosen?
How Classloader determines which classes it can load?
Where does bytecode injection happen?
I'm curious about how do annotations work in a popular Spring framework.
Possible solution
As far as I understand, two mechanisms might be used:
1. Bytecode injection on classloading
Spring could use its own classloader to load required classes. At runtime, when the class is loaded and Spring determines it has some appropriate annotation, it injects bytecode to add additional properties or behavior to the class.
So a controller annotated with #Controller might be changed to extend some controller base class and a function might be changed to implement routing when annotated with #RequestMapping.
#Controller
public class HelloWorldController {
#RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
2. Reflection used for instantiation
#Autowired could be read by reflection at runtime by the BeanFactory to take care of the instantiation order and instantiate the configured properties.
public class Customer
{
private Person person;
#Autowired
public void setPerson(Person person) {
this.person = person;
}
}
Question
How do Spring annotations really work?
Spring is open source so you don't need to figure how it work, look inside:
RequestMapping annotation is handled by RequestMappingHandlerMapping, see getMappingForMethod method.
Autowired annotation is handled by AutowiredAnnotationBeanPostProcessor, see processInjection method.
Both use reflection to get annotation data and build the handler mapping info in the first case or populate the bean in the second one.
Spring context understand annotation by set of classes which implements bean post processor interface. so to handle different type of annotation we need to add different annotation bean post processors.
if you add <context:annotation-config> in you configuration xml then you need not to add any annotation bean post processors.
Post processor provide methods to do pre and post processing for each bean initialization.
you can write your own bean post processors to do custom processing by created a bean which implements BeanPostProcessor interface.
In my project I have an interface annotated with org.springframework.stereotype.Service tag.
I have two different implementation for this interface.
In my manage bean, I am injecting interface Service class and using its methods.
Now my requirement is, in run time I have to pick particular implementation (lets say based on login user group) so that respective logic can be invoked.
As per my understanding, we can achieve this using Factory pattern in java and achieve the same.
How can we implement this in SPRIng???
Besides suggested related topic above, there is a good thread on JavaRanch.
You can use
#Qualifier("myServiceImpl1") annotation together with #Autowired. In
that case this particular implementation of the interface will be
injected. You should also use the same name with your #Component,
#Service or #Repository annotations e.g.
#Service("myServiceImpl1")
public class MyServiceImpl1 implements MyService{}
public class Consumer{
#Autowired
#Qualifier("myServiceImpl1")
public MyService myServiceImpl1;
}
#Primary together with #Component, #Service or #Repository
annotations in your implementation class, in that case this
implementation will be injected by default.
If you mark a list of some interface type with #Autowired, all
available implementations of this interface will be injected.
#Autowired
public List<MyService> allAvailableImplementations;
I'm using spring mvc 3.1.x and jets3t.
I have a DataAccessObject that i instantiate as a Singleton bean..
I managed to get it working through extending the applicationcontextloader class and adding it to the web.xml
EDIT:
I changed my method, I tried inject and autowired but it's not suitable for my needs.
What I've done was to implement ApplicationContextAware and set it up as a bean, in the code I use it as follows:
ApplicationContext ctx = BannerApplicationContext.getApplicationContext();
BannerGenericDAO bdao = (BannerGenericDAO) ctx.getBean("dao");
I'm new to Spring and in general the servlet world..
Questions are:
what's the best way of doing this? Is this considered a "best-practice"?
How do you inject an object, keeping other method fields that are not supplied by autowiring?
How do you get an object to be used throughout the entire application?
Thanks!!
You could use annotations in your controller.
#Controller
public class MyController{
#Autowired // or #Inject, which is more JEEish (JSR330).
private SomeDao daoService;
}
Given "SomeDao" is the type of your singleton DAO, of course.