Using #Qualifier and #Bean together in Java Config Spring - spring

I have follow code
interface Drivable {
}
#Component
class Bmw implements Drivable {
}
#Component
class Mercedes implements Drivable {
}
class Driver {
private Drivable drivable;
public Driver(Drivable drivable) {
this.drivable = drivable;
}
}
And Spring Java Config
#Configuration
#ComponentScan
class CarConfig {
#Bean
#Qualifier("mercedes")//the code won't work
public Driver getDriver(Drivable drivable) {
return new Driver(drivable);
}
#Bean//I've added the bean
public Drivable getMercedes() {
return new Mercedes();
}
}
Can I use #Qualifier annotation with #Bean annotation if I want to specify type of object that should pass to method? I can't find in Spring doc how I can solve the problem. Thx.

I think you got the usage of #Qualifier bit wrong.
If we have more than one bean that qualifies for spring injection, then we use #Qualifer to specify which needs to be used for injection.
In this case you have two beans Bmw and Mercedes both implementing Drivable interface.
Presuming I got your intent correct, you want spring to inject Mercedes bean into the Driver object.
So for that, you need to specify public Driver getDriver(#Qualifier("mercedes") Drivable drivable) in the CarConfig class.
#Configuration
#ComponentScan
class CarConfig {
#Bean
public Driver getDriver(#Qualifier("mercedes") Drivable drivable) {
return new Driver(drivable);
}
And then you can use AnnotationConfigApplicationContext to load the spring context and subsequently get the Driver bean as below:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(CarConfig.class);
Driver bean = ctx.getBean(Driver.class);
}
}
Just to extend the example, let us say if you want to create a Driver bean for each of Bmw and Mercedes then the sample code would be:
#Configuration
#ComponentScan
class CarConfig {
#Bean(name="mercedesDriver")
public Driver getMercedesDriver(#Qualifier("mercedes") Drivable drivable) {
return new Driver(drivable);
}
#Bean(name="bmwDriver")
public Driver getBmwDriver(#Qualifier("bmw") Drivable drivable) {
return new Driver(drivable);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(CarConfig.class);
System.out.println(Arrays.asList(ctx.getBeanNamesForType(Driver.class)));
Driver mercedesBean = ctx.getBean("mercedesDriver", Driver.class);
Driver bmwBean = ctx.getBean("bmwDriver", Driver.class);
}
}

#Configuration
#ComponentScan
class CarConfig {
#Bean
public Driver mercedesDriver(Drivable bmw) {
return new Driver(bmw);
}
// same as
#Bean("mercedesDriver")
public Driver getDriver(Drivable bmw) {
return new Driver(bmw);
}
.....
#Autowired private Driver mercedesDriver;
In Spring you an relate on dependency injection by name. In the first example the name is defined by the method name. In the second example the method name is not important, because wie name the bean through the Annotation. Its very easy and simple. Not really need for #Qualifier. Only if the name should be different, but why?

You could define qualifiers for each specific implementations of interface Drivable. Once you did, now you could autowire them into CarConfig class and you have to be create Beans for each Drivers(Mercedz & Benz) along with qualifier names.
Find below Implementation:
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface Bmw {
}
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface Mercedes {
}
Now your Interface Implementations of Driver should be annotated with Qualifiers as below
#Compoenent
#Bmw
public interface Bmw implements Drivable{
}
#Component
#Mercedes
public interface Mercedes implements Drivable{
}
Your CarConfig class should be as below:
#Configuration
public class CarConfig{
#autowire
#Bmw
private Drivable bmwDriver;
#autowire
#Mercedes
private Drivable mercedesDriver;
#Bean
public Bean getBmwDriver(){
return new Bmw(bmwDriver);
}
#Bean
public Bean getMercedesDriver(){
return new Mercedes(mercedesDriver);
}
}
NOTE: if you are creating bean with #Bean, it will be injected byType if there is duplicates then it will injected byName. we no need to mention #Bean(name="bmwDriver") .
so you can directly use qualifier("bmwDriver") wherever you need in classes.

Related

Spring bean with same method name but different qualifier fail to load

I have two Spring Configuration classes defined as follows
#Configuration
public class ClsA {
#Bean
#Qualifier("ClasA")
public String getSomething(){
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean
#Qualifier("ClsB")
public String getSomething(){
return "somethingB";
}
}
Both have the same method name. Even though qualifiers are different, the application doesn't load as it only injects one and wherever the other one is injected, if fails with noBeanDefinition exception let's say for ClsB bean qualifier.
When I keep the method name different and everything loads hunky dory.
Is this behavior normal ? Why doesn't spring load these beans just fine as they have different qualifiers ?
The #Qualifier annotation is supposed to be used at injection points to resolve ambiguity as to which bean to inject. But in the example, you use it at bean declaration site. At declaration site, you can give a name to each bean by specifying it in #Bean annotation. So if you leave your methods with the same name, then a valid example can be as follows:
#Configuration
public class ClsA {
#Bean("ClasA")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("ClasB")
public String getSomething() {
return "somethingB";
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ClsB.class, ClsA.class})
public class ClsTest {
#Autowired
#Qualifier("ClasA") //this is the place where #Qualifier can be used
String smthA;
#Autowired
#Qualifier("ClasB")
String smthB;
#Test
public void test() {
System.out.println(smthA);
System.out.println(smthB);
}
}
Output:
somethingA
somethingB
1. Customize Bean Naming
Each bean name must be unique.
1.3.1. Naming Beans
1.12.3. Using the #Bean Annotation > Customizing Bean Naming
#Configuration
public class ClsA {
#Bean("clasAText")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("clsBText")
public String getSomething() {
return "somethingB";
}
}
2. (Optional) Add qualifier metadata
1.10.5. Defining Bean Metadata within Components
#Configuration
public class ClsA {
#Bean("clasAText")
#Qualifier("clsA")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("clsBText")
#Qualifier("clsB")
public String getSomething() {
return "somethingB";
}
}
3-1. Inject by name
1.9.7. Injection with #Resource
#Component
public class MyComponent {
#Resource(name = "clasAText")
private String text;
// ...
}
Note:
if you intend to express annotation-driven injection by name, do not primarily use #Autowired (snip). Instead, use the JSR-250 #Resource annotation
3-2. Inject by qualifier
1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers
If qualifiers have been added, these are available.
#Component
public class MyComponent {
#Autowired
#Qualifier("clsA")
private String text;
// ...
}
This answer is a fallback behavior. Name and qualifier are different one.
1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers
For a fallback match, the bean name is considered a default qualifier value.

Spring boot defining configuration beans per user

I am using Spring boot. I have some question regarding the spring boot beans.
But I have doubt
I use bean which are default scope that is singleton. So they will have only one instance per application.
#Configuration
public class ...{
#Bean
public void method() {}
}
And
Now i use bean which scope is prototype. So they will have each instance per request.
#Configuration
public class ...{
#Bean
#Scope("prototype")
public void method() {}
}
But
I want single instance per user..? all request use single instance per user.
#Configuration
class Abc {
#Bean
#Scope("session")
public YourBean getYourBean() {
return new YourBean();
}
}
You will need to define one singleton bean with a property using prototype bean:(xml example)
With #bean definition:
#Component
#Scope("singleton")
public class SingletonBean {
// ..
#Autowired
private PrototypeBean prototypeBean;
//..
}
#Component
#Scope("prototype")
public class PrototypeBean {
//.......
}
Example: https://www.baeldung.com/spring-inject-prototype-bean-into-singleton

Spring AOP proxy and interface implementation

I'm trying to understand Spring proxy mechanism and I have problem with one thing.
I have Interface:
public interface MyInterface{
void myMethod();
}
and implementing class:
#Component
public class MyBean implements MyInterface{
#Override
public void myMethod(){
//do something
}
}
Now I create Aspect, for example:
#Aspect
#Component
public class LogAspect {
#Before("execution(public * *(..))")
public void logBefore() {
System.out.println("Before aspect");
}
}
And I have simple starter class:
#Configuration
#ComponentScan
#EnableAspectJAutoProxy
public class SpringAopApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
SpringAopApplication.class);
MyBean bean = ctx.getBean(MyBean.class);
// MyInterface bean = ctx.getBean(MyInterface.class); //works
bean.myMethod();
ctx.close();
}
}
According to the Spring docs we can read:
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
But I got an error No qualifying bean of type [MyBean] is defined. It works only when I enable CGLib proxying by #EnableAspectJAutoProxy(proxyTargetClass = true).
Can someone explain what I am missing here? Why MyBean is not discovered when using AOP? ctx.getBean(MyInterface.class) works, but I can't imagine the situation with many implementations of such interface.
The target object to be proxied (MyBean) implements at least one interface (MyInterface), so a JDK proxy is used.
This proxy implements MyInterface, but is NOT an instance of MyBean.
Thats why
MyInterface bean = ctx.getBean(MyInterface.class);
works and
MyBean bean = ctx.getBean(MyBean.class);
not.
CGLib proxies are created by subclassing the target object, so the bean created is a subclass of MyBean and implements MyInterface.
In this case also
MyBean bean = ctx.getBean(MyBean.class);
works.
...but I can't imagine the situation with many implementations of such interface.
The only reason for MyInterface could be, to allow spring to create a JDK proxy, so there is no need to have many implementations.
Because if you check up your bean class you'll find com.sun.proxy.$Proxy21 (or something similar) instead, which wraps your method. They are incompatible types even they have the same interface.
For example:
public interface AnInterface {
void func();
}
public class Bb implements AnInterface{
#Override
public void func() {
System.out.println("bb");
}
}
public class Cc implements AnInterface{
#Override
public void func() {
System.out.println("cc");
}
}
So when you call
public static void main(String[] args) {
Bb b = new Bb();
Cc c=b; // Error
AnInterface c=b; // Ok
}

Multiple Spring Configuration files (one per Profile)

I'm a Spring rookie and trying to benefit from the advantages of the easy 'profile' handling of Spring. I already worked through this tutorial: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile and now I'd like to adapt that concept to an easy example.
I've got two profiles: dev and prod. I imagine a #Configuration class for each profile where I can instantiate different beans (implementing a common interface respectively) depending on the set profile.
My currently used classes look like this:
StatusController.java
#RestController
#RequestMapping("/status")
public class StatusController {
private final EnvironmentAwareBean environmentBean;
#Autowired
public StatusController(EnvironmentAwareBean environmentBean) {
this.environmentBean = environmentBean;
}
#RequestMapping(method = RequestMethod.GET)
Status getStatus() {
Status status = new Status();
status.setExtra("environmentBean=" + environmentBean.getString());
return status;
}
}
EnvironmentAwareBean.java
public interface EnvironmentAwareBean {
String getString();
}
EnvironmentAwareBean.java
#Service
public class DevBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "development";
}
}
EnvironmentAwareBean.java
#Service
public class ProdBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "production";
}
}
DevConfig.java
#Configuration
#Profile("dev")
public class DevConfig {
#Bean
public EnvironmentAwareBean getDevBean() {
return new DevBean();
}
}
ProdConfig.java
#Configuration
#Profile("prod")
public class ProdConfig {
#Bean
public EnvironmentAwareBean getProdBean() {
return new ProdBean();
}
}
Running the example throws this exception during startup (SPRING_PROFILES_DEFAULT is set to dev):
(...) UnsatisfiedDependencyException: (...) nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [EnvironmentAwareBean] is defined: expected single matching bean but found 3: prodBean,devBean,getDevBean
Is my approach far from a recommended configuration? In my opinion it would make more sense to annotate each Configuration with the #Profile annotation instead of doing it for each and every bean and possibly forgetting some variants when new classes are added later on.
Your implementations of EnvironmentAwareBean are all annotated with #Service.
This means they will all be picked up by component scanning and hence you get more than one matching bean. Do they need to be annotated with #Service?
Annotating each #Configuration with the #Profile annotation is fine. Another way as an educational exercise would be to not use #Profile and instead annotate the #Bean or Config classes with your own implementation of #Conditional.

Java class xml vs java bean autowiring

In xml defined beans you can define two classes like this
<bean id="classA" class="ex.ClassA"/>
<bean id="classB" class="ex.classB"/>
Then in your java implementation you can autowire the constructor of one of the classes in example
public class ClassA {
#autowired
public(ClassB classB){
this.classB = classB;
}
Now how does one do that with java config beans since in example
#Bean
public ClassA classA(){
return new ClassB();
}
#Bean
public ClassB classB(){
return new ClassB()
}
the compiler would warn that Class a does not have any such constructor, how does one do that in java, with autowiring?
Thanks all
See http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java-injecting-dependencies
Note that the ClassB bean is implicitly a singleton. The use of the annotation #Configuration on the Config class ensures that Spring returns the singleton instance of the ClassB bean in the classB() call.
#Configuration
public class Config {
#Bean
public ClassA classA(){
return new ClassA( classB() );
}
#Bean
public ClassB classB(){
return new ClassB();
}
}
Or you may prefer this approach (Spring 4.2.1+ required)
#Configuration
#Import(ClassA.class)
public class Config {
#Bean
public ClassB classB(){
return new ClassB();
}
}
#Component
public class ClassA {
#Autowired
public ClassA(ClassB classB) {
...
}
}
Pass the beans you want as parameters to the #Bean method, or use component scanning to create the dependent bean implicitly.

Resources