I have seen the AutoConfiguration classes, that defines #Configuration within an #Configuration and these are all static. Why they should be static? Is it a better way.
What is the difference between the #Configuration defined within #Component class and stand-alone #Configuration class?
Take a look at the definition of WebMvcAutoConfigurationAdapter in the source code for WebMvcAutoConfiguration to find your answer:
// Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not
// on the classpath
#Configuration
#Import(EnableWebMvcConfiguration.class)
#EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
...
}
The auto-configuration classes are defined as nested static classes to prevent Spring's component-scanning from picking them up automatically when the proper annotation has not been used. So a good rule of thumb would be to define your configuration classes as stand-alone classes if you expect them to be used every time, or as nested static classes if you'd like to isolate them from classpath scanning.
Related
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.
Is there any difference between behaviour of #Configuration and #Componentannotation in Spring framework?
Is there any situation when changing #Configuration to #Component will change program's behaviour?
I did a few experiments and from what I see so far, they always work the same.
Notice that I'm interested specifically in the difference of behaviour - I already know that the two annotations are usually used in different situations.
Your #Configuration class can be annotated also with #ComponentScan
we use the #ComponentScan annotation along with #Configuration annotation to specify the packages that we want to be scanned
If you change to #Component it won't work as expected
See also difference between #Configuration and #Component
#Configuration is also a #Component but a #Component cannot act like a #Cofinguration
While they both make annotated classes beans, they serve different purposes.
Treat a class with #Configuration as a part of your application context where you define beans. Usually, you have #Bean definitions in your #Configuration class.
#Component annotation, on the other hand, means that your class IS a bean itself and that it.
So, for example you need a bean MyService.
You can define it in two ways:
#Configuration
public class MyAppConfig {
#Bean
public MyService myService(){
return new MyServiceImpl();
}
}
or just
#Component
public class MyServiceImpl {
...
}
So, when you use your #Configuration as a configuration, adding things specific to it (#ComponentScan, #Bean, ...) it would have a different behaviour and it won't work with just #Component instead.
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.
I have two classes marked as #SpringBootApplication under one directory:
#SpringBootApplication
public class FirstSpringBootApplication
and
#SpringBootApplication
public class SecondSpringBootApplication
#SpringBootApplication annotation contains #ComponentScan annotation and #EnableAutoConfiguration annotation. So, each of two of these classes will consider another as #Configuration bean. How to exclude FirstSpringBoodApplication from component scanning by SecondSpringBootApplication without using profiles?
The annotate class with below annotations will work similarly as #SpringBootApplication. It also does the same, and the excludeFilter is important, which is used to specify which class not to include while scanning.
#EnableAutoConfiguration
#ComponentScan(excludeFilters={#Filter(type=CUSTOM, classes={TypeExcludeFilter.class})})
In case you need to define two or more excludeFilters criteria, you have to use the array.
For instances in this section of code I want to exclude all the classes in the org.xxx.yyy package and another specific class, MyClassToExclude
i'm wondering if spring loads an interface when declared as an #autowired attribute of an implementation class without having annotated the interface as a #component .
let me describe my problem a bit more :
i have both an interface and its implementation class have the same name but they reside in different packages . i annotated the implementation as #Component("myImplementation") .
but i end up having an exception that says :
conflicts with existing, non-compatible bean definition of same name and class
i'm thinking of excluding interfaces from <context:component-scan , what do you think ?
PS : my interface isn't #Component annotated , the application runs just fine on developpement environement , i only get the error after Proguard obfuscation
Your proguard.conf should be contain:
## ... preserve class annontation (Java EE 1.6 DI)
# Spring3
#-keep #org.springframework.stereotype.Service class *
-keep #org.springframework.stereotype.Controller class *
#-keep #org.springframework.stereotype.Component class *
#-keep #org.springframework.stereotype.Repository class *
proguard forums has more detailed answers.
Annotating your implementation with #Component and not annotating your interface is usually the right way to set things up. Spring's auto-wiring will look for a managed bean of a matching type, and your implementation will match for a field typed to the interface. If your interface is not annotated with #Component, or any Spring stereotype annotation, it should not be loaded into the context during a component scan. So, you should not have a problem if the interface and implementation have the same class name.
Are you sure you've tried not annotating the interface? Are you sure you don't have some other class somewhere else in your project that also has the same name as the interface and its implementation?
Well I think moving interfaces in different package would work because you would create object reference of interface and respective implementation beans would be auto wired to those object references. But you should follow naming conventions. There would be problem when differentiating interfaces and implementation classes as names are same. Follow standards like
interface SomeInterface {
//....
}
for implementation class of SomeInterface
class SomeInterfaceImpl implements SomeInterface {
// implementation....
}