Spring Autowiring calling wrong constructor - java

I'm learning Springs with annotations and auto wiring. I tried three types of auto wiring
Constructor
Setter injection
Method
This is my configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- add entry for component scanning -->
<context:component-scan base-package="com.aht.spring.entity"></context:component-scan>
</beans>
These are my entities
Coach.java
package com.aht.spring.entity.coach;
public interface Coach {
String getDailyWorkOut();
String getDailyFortune();
}
FortuneService
package com.aht.spring.entity.fortune;
public interface FortuneService {
String getFortune();
}
HappyFortuneService
package com.aht.spring.entity.fortune;
import org.springframework.stereotype.Component;
#Component
public class HappyFortuneService implements FortuneService {
public String getFortune() {
return "Feel energetic for first half of trainning";
}
}
FootBallCoach
package com.aht.spring.entity.coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.aht.spring.entity.fortune.FortuneService;
#Component
public class FootBallCoach implements Coach {
private FortuneService fortuneService;
#Autowired
public FootBallCoach(FortuneService fortuneService) {
this.fortuneService = fortuneService;
}
public String getDailyWorkOut() {
return "Practice one-on-one for 2 hours";
}
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
CricketCoach
package com.aht.spring.entity.coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.aht.spring.entity.fortune.FortuneService;
#Component
public class CricketCoach implements Coach {
private FortuneService fortuneService;
public CricketCoach() {
System.out.println("Default constructor");
}
#Autowired
public void setFortuneService(FortuneService fortuneService) {
this.fortuneService = fortuneService;
}
public String getDailyWorkOut() {
return "Practice out field tips";
}
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
BaseBallCoach
package com.aht.spring.entity.coach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.aht.spring.entity.fortune.FortuneService;
#Component
public class BaseBallCoach implements Coach {
private FortuneService fortuneService;
public String getDailyWorkOut() {
return "Practice curve whole day";
}
public String getDailyFortune() {
return fortuneService.getFortune();
}
#Autowired
public void customAutoWire(FortuneService fortuneService) {
this.fortuneService = fortuneService;
}
}
I've three classes for executing three ways of auto wiring, Constructor and Setter worked fine, but when method wise auto wiring was done a wrong constructor was called. One thing I missed in my in my BaseBallCoach class was a default constructor, but anyhow compiler will automatically generate one for me right?
This is my CoachMethodInjectionApp.java where I executed method auto wiring
package com.aht.spring.app;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.aht.spring.entity.coach.Coach;
public class CoachMethodInjectionApp {
public static void main(String[] args) {
// read config-file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// get beans
Coach coach = context.getBean("baseBallCoach", Coach.class);
// get dependencies
System.out.println(coach.getDailyFortune());
// get daily workout
System.out.println(coach.getDailyWorkOut());
// close context
context.close();
}
}
This was the output
Default constructor
Feel energetic for first half of trainning
Practice curve whole day
First line of output is what I don't understand Default constructor, why the constructor of CricketCoach executing??

As CricketCoach class is annotated with #Component and the package is scanned when the Spring container starts it will create an instance of type CricketCoach by calling the no-arg constructor
All the beans defined in the xml file or annotated with #Component or any extension of #Component from scanned packages will be created at start time of the spring container no matter if they will be used or not

You're creating a new instance of Coach class here:
Coach coach = context.getBean("baseBallCoach", Coach.class);
Everytime new instance is created it is executing a constructor. In which you have call to System.out.println("Default constructor");. You may try removing #Component from Cricket Coach imlpementation.

Related

Spring Bean Config

I'm learning the bean AOP with Annotation and xml config but Spring does not create the beans.
Interface
package com.spring.studying.SpringAop.FrameworkService.AspectJAnnotation;
public interface Artist {
void perform();
}
Guitar Class
package com.spring.studying.SpringAop.FrameworkService.AspectJAnnotation;
import org.springframework.stereotype.Component;
#Component("grammyGuitarist")
public class GrammyGuitarist implements Artist{
#Override
public void perform() {
System.out.println("Start to play guitar");
}
public void playGuitar(String brand)
{
System.out.println("Get Guitar "+brand);
}
public void rest()
{
System.out.println("zzZZ!!!!");
}
}
Documentarist
package com.spring.studying.SpringAop.FrameworkService.AspectJAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component(value="documentaries")
public class Documentarist {
private GrammyGuitarist guitarist;
public void executed()
{
guitarist.playGuitar("LakeWood");
guitarist.perform();
guitarist.rest();
}
#Autowired
public void setGuitarist(GrammyGuitarist guitarist) {
this.guitarist = guitarist;
}
}
Advice Class
package com.spring.studying.SpringAop.FrameworkService.AspectJAnnotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Component("annotatedAdvice")
#Aspect
public class AnnotatedAdvice {
#Pointcut("execution(* rest*(..)) && args(brand)")
public void restExecution(String brand)
{
}
#Pointcut("bean(grammyGuitarist)")
public void isGrammyGuitarist()
{
}
#Before("restExecution(brand) && isGrammyGuitarist")
public void simpleBeforeAdvice(JoinPoint joinPoint , String brand)
{
System.out.println("Before Advice processing");
System.out.println("Playing guitar :" + brand);
System.out.println("Executing :"+ joinPoint.getSignature().getDeclaringTypeName() +" "+joinPoint.getSignature().getName());
}
}
Demo Class
package com.spring.studying.SpringAop.FrameworkService.AspectJAnnotation;
import org.springframework.context.support.GenericXmlApplicationContext;
import java.util.Arrays;
public class AspectJAnnotationDemo {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("aop-aspectj-annotation-style.xml");
ctx.refresh();
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
Documentarist documentarist = ctx.getBean("documentaries",Documentarist.class);
documentarist.executed();
}
}
My Xml Config File
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<context:annotation-config/>
<context:component-scan base-package="com.spring.studying.SpringAop"/>
<aop:aspectj-autoproxy/>
</beans>
None of my beans were created just 6 default beans from spring.
I have try to create bean with tag and it worked fine . Just don't know why my code did not work with the annotation.
restExecution #Pointcut is wrong, because rest method of GrammyGuitarist doesn't take any arguments. playGuitar method takes brand argument, so you need to change your pointcut a bit:
#Component("annotatedAdvice")
#Aspect
public class AnnotatedAdvice {
#Pointcut("execution(* play*(..)) && args(brand)")
public void playExecution(String brand) {
}
#Pointcut("bean(grammyGuitarist)")
public void isGrammyGuitarist() {
}
#Before("playExecution(brand) && isGrammyGuitarist()")
public void simpleBeforeAdvice(JoinPoint joinPoint, String brand) {
System.out.println("Before Advice processing");
System.out.println("Playing guitar :" + brand);
System.out.println("Executing :" + joinPoint.getSignature().getDeclaringTypeName() + " " + joinPoint.getSignature().getName());
}
}
When you do this, aspects will indeed be created, but you will start getting exceptions:
Bean named 'grammyGuitarist' is expected to be of type 'com.example.demo.aspect.GrammyGuitarist' but was actually of type 'jdk.proxy2.$Proxy14'
This is because GrammyGuitarist implements an interface, and in this case Spring AOP uses JDK dynamic proxies
The simplest solution would be to force the use of a CGLIB proxy. To do this, you need to add an annotation above the aspect:
#EnableAspectJAutoProxy(proxyTargetClass = true)
After that, the program will give the expected result:
annotatedAdvice
documentaries
grammyGuitarist
org.springframework.aop.config.internalAutoProxyCreator
Before Advice processing
Playing guitar :LakeWood
Executing :com.example.demo.aspect.GrammyGuitarist playGuitar
Get Guitar LakeWood
Start to play guitar
zzZZ!!!!
In Spring Boot, CGLIB enforcement is enabled by default. Check this question for better understanding

Spring Not Calling PostConstruct method when XML config is used but works when Java Config is used

I have following class
import com.ujjwal.model.Speaker;
import com.ujjwal.repository.SpeakerRepository;
import javax.annotation.PostConstruct;
import java.util.List;
public class SpeakerServiceImpl implements SpeakerService {
private SpeakerRepository repository;
public SpeakerServiceImpl() {
System.out.println("inside No Args Constructor");
}
public SpeakerServiceImpl(SpeakerRepository repository) {
System.out.println("inside Args Constructor");
this.repository = repository;
}
#PostConstruct
private void initialize() {
System.out.println("Post Construct Init");
}
public void setSpeakerRepository(SpeakerRepository repository) {
System.out.println("In setSpeakerRepository");
this.repository = repository;
}
public List<Speaker> findAll() {
return repository.findAll();
}
}
And following is my xml config file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="speakerRepository"
class="com.ujjwal.repository.HibernateSpeakerRepositoryImpl"/>
<!--<bean name="speakerRepositoryUj"
class="com.ujjwal.repository.UjjwalSpeakerRepositoryImpl"/>-->
<bean name="speakerService"
class="com.ujjwal.service.SpeakerServiceImpl">
<constructor-arg index="0" ref="speakerRepository"/>
</bean>
</beans>
Also, I made sure that my pom.xml has javax.annotation libraray and maven included it in external libraries.
Now, following is my Application class which has main method:
import com.ujjwal.service.SpeakerService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
public static void main(String args[]) {
ApplicationContext appContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
SpeakerService service = appContext.getBean("speakerService", SpeakerService.class);
System.out.println(service.findAll().get(0).getFirstName());
}
}
Now, I am not seeing print statement of initialize method in my output. And following is the output:
inside Args Constructor
Ujjwal
But I get the print statement of initialize method when instead of using xml config I use Java Configuration for Beans.
Can anyone please explain what is happening here?

BeanPostProcessor methods are not getting invoked

I am trying to understand the sequence of static initialization, instance initialization, InitializingBean and BeanPostProcessor, so I created below example, everything is working except that BeanPostProcessor are not getting invoked, am I missing something?
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Component;
#Component
public class SpringTest {
#Autowired
Person person;
public static void main(String[] args) {
testApplicationContext();
}
private static void testApplicationContext() {
// here static and instance initializers of Person class will be invoked right away, even when we are not calling getBean method
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\E_Drive\\Projects\\Workspace\\Test\\CS101\\src\\com\\learn\\stackoverflow\\general\\bean.xml");
ApplicationContext applicationContext2 = new FileSystemXmlApplicationContext("C:\\E_Drive\\Projects\\Workspace\\Test\\CS101\\src\\com\\learn\\stackoverflow\\general\\bean.xml");
// notice that above you are creating 2 ioc containers, and since they are different ioc containers so it is possible to have 2 singletons in JVM.
SpringTest springTest = (SpringTest) applicationContext.getBean("springTest");
}
}
Person class:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope(value="singleton")
public class Person implements InitializingBean, BeanPostProcessor {
#Autowired
SpringTest springTest;
static{
System.out.println("Static initialization");
}
{
System.out.println("Instance initialization");
}
public void sayHello(){
System.out.println("Hello");
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet");
}
#Override
public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("BeanPostProcessor.postProcessAfterInitialization : " + arg1);
return arg0;
}
#Override
public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
System.out.println("BeanPostProcessor.postProcessBeforeInitialization : " + arg1);
return arg0;
}
}
Bean XML file:
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.learn.stackoverflow.general"/>
<context:annotation-config />
<!-- <bean id = "person" class = "com.learn.stackoverflow.general.Person" scope="singleton">
</bean> -->
<bean id = "springTest" class = "com.learn.stackoverflow.general.SpringTest" scope="singleton">
</bean>
</beans>
Output:
Static initialization
Instance initialization
InitializingBean.afterPropertiesSet
Instance initialization
InitializingBean.afterPropertiesSet
Is there anything else required for BeanPostProcessor methods to be invoked?
A bean cannot self-post-process, the post-processor needs to be a separate bean; see tutorial.

Which object will be used when I have bean definition in config file as well as using #Autowire annotation

I am looking at some existing application code and I am confuse because of the code over there, here is the scenario:
In the class ABC, I have autowiring as:
#Autowired
RestTemplate restTemplate;
Then in my spring bean config file, I bean definition as:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
In the class ABC I am using rest template as:
restTemplate.postForObject(url, requestObject, String.class);
My questions are:
when I am using the rest template then the object which I am using is the one which is because of autowiring or the one which is defined in bean config file?
In case of autowiring since I have not specified the scope, so it will be singleton, right?
As per comments and answers, below is minimalistic reproducible code which shows that even when I have auto-wiring and bean definition in bean config file, I can run the program and there are no issues.
Main class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class SpringTest {
#Autowired
Person person;
public static void main(String[] args) {
generalTest();
}
private static void generalTest() {
testApplicationContext();
}
private static void testApplicationContext() {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("bean.xml");
SpringTest springTest = (SpringTest) applicationContext.getBean("springTest");
if(springTest.person == null){
System.out.println("person is NULL");
} else{
System.out.println("person is not NULL");
}
}
}
Bean file:
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.learn.stackoverflow.general"/>
<!-- as such below is useless because The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>.
There is usually no need to include the <context:annotation-config> element when using <context:component-scan>. -->
<context:annotation-config />
<bean id = "person" class = "com.learn.stackoverflow.general.Person" scope="singleton">
</bean>
</beans>
Person class:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope(value="singleton")
public class Person implements InitializingBean, Human {
#Autowired
SpringTest springTest;
static{
System.out.println("Static initialization from Person");
}
{
System.out.println("Instance initialization from Person");
}
public Person(){
System.out.println("Constructor from Person");
}
public void sayHello(){
System.out.println("Hello");
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet from Person");
}
#Override
public void breathe() {
System.out.println("person is breathing...");
}
}
Output is person is not NULL
The config file tells Spring to create a bean with an id of "restTemplate" which is of type org.springframework.web.client.RestTemplate. The default scope is a single instance of the bean.
Then in the code, since there exists a bean of type RestTemplate, the bean (which happens to have an id of "restTemplate" is auto wired.
"restTemplate" as an id or a class attribute that also has "restTemplate" as its name is not important. The bean can be injected since it's of same type. (And also beceause there's only 1 of that type.)
#Autowired doesn't create bean, it will take the existing bean declaration that match with the expected type and put it in the field. In the XML you have your bean declaration, without it your bean won't exist (unless you are using Spring Boot, in which case it might get automatically created if it doesn't exists).
You can use now #Inject instead of #Autowired since JSR-299 and if you have a recent version of Spring and javax.inject dependencies. Both do exactly the same thing but #Inject is clearer.
When IoC container finds a bean definition defined in the bean config file then same definition is used for injecting the instance, and if IoC container doesn't find one then it creates an instance and injects the same.
Below is a little tweaked example which demonstrates above concept, you can play around with it my commenting and uncommenting the bean definition mentioned in bean config file. Please read carefully my code comments.
SpringTest:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class SpringTest {
#Autowired
Person person;
public static void main(String[] args) {
generalTest();
}
private static void generalTest() {
testApplicationContext();
}
private static void testApplicationContext() {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\E_Drive\\Projects\\Workspace\\Test\\CS101\\src\\com\\learn\\stackoverflow\\general\\bean.xml");
SpringTest springTest = (SpringTest) applicationContext.getBean("springTest");
if(springTest.person == null){
System.out.println("person is NULL");
} else{
System.out.println("person is not NULL");
springTest.person.sayHello(); // here output will be “Hello, ppj” if you keep the config file bean definition and when you remove that bean definition then output is “Hello, null”
}
}
}
Bean config:
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.learn.stackoverflow.general"/>
<!-- once you get comment out below, IoC will instatiate a bean and will inject the same in SpringTest's autowiring of Person class -->
<!-- <bean id = "person" class = "com.learn.stackoverflow.general.Person" scope="singleton">
<constructor-arg name="name" value="ppj"></constructor-arg>
</bean> -->
</beans>
Person:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope(value="singleton")
public class Person {
private String name;
#Autowired
SpringTest springTest;
public Person(){
System.out.println("Constructor from Person");
}
public Person(String name){
System.out.println("String Constructor from Person");
this.name = name;
}
public void sayHello(){
System.out.println("Hello, " + name);
}
}

Spring is picking an interface implementation out of many, on its own?

Friends below is my code, I am trying to run dependency Injection with Spring
I have an interface, two class implementations of that interface.
One bean.xml and One main method class.
Interface IWriter.java
package DI;
public interface IWriter {
public void writer(String s);
}
Class Writer.java
package DI;
import org.springframework.stereotype.Service;
#Service
public class Writer implements IWriter {
public void writer (String s){
System.out.println(s);
}
}
Class NiceWriter.java
package DI;
import org.springframework.stereotype.Service;
#Service
public class NiceWriter implements IWriter {
public void writer (String s){
System.out.println("The string is " + s);
}
}
Another class
package DI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
#Service
public class MySpringBeanWithDependency {
#Autowired
private IWriter writer;
public void run() {
String s = "This is my test";
writer.writer(s);
}
}
Main.java
package DI;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import DI.MySpringBeanWithDependency;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
BeanFactory factory = context;
MySpringBeanWithDependency test = (MySpringBeanWithDependency) factory.getBean("mySpringBeanWithDependency");
test.run();
}
}
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="DI" />
</beans>
When I run the code Spring container gives the output of the method of Writer.java class. I haven't anywhere specified which implementation to pick. How is Spring picking up the implementation of Writer.java??
change your code as follows.
Class Writer.java
package DI;
import org.springframework.stereotype.Service;
#Service("writer")
public class Writer implements IWriter {
public void writer (String s){
System.out.println(s);
}
}
Class NiceWriter.java
package DI;
import org.springframework.stereotype.Service;
#Service("niceWriter")
public class NiceWriter implements IWriter {
public void writer (String s){
System.out.println("The string is " + s);
}
}
Another class
package DI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
#Service
public class MySpringBeanWithDependency {
#Autowired
#Qualifier("writer")//if you need to autowire Writer service
private IWriter writer;
#Autowired
#Qualifier("niceWriter")//if you need to autowire NiceWriter service
private IWriter niceWriter
public void run() {
String s = "This is my test";
writer.writer(s);
}
}
When there is more than one implementation of interface and you use #Autowired in that case spring bind any of the class. but if you want to autowire specific implementation then you can use
#Qualifier( "<implementing class name>" )
#Qualifier documentation
Few things that you must know about Spring is
All spring beans are managed - they "live" inside a container, called "application context".
Each application has an entry point to that context. Also, there is a place where the application context is bootstrapped and all beans - autowired. In web applications this can be a startup listener.
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
Try this one.
Class Writer.java
package DI;
import org.springframework.stereotype.Service;
#Service("writer")
public class Writer implements IWriter {
public void writer (String s){
System.out.println(s);
}
}
Class NiceWriter.java
package DI;
import org.springframework.stereotype.Service;
#Service("niceWriter")
public class NiceWriter implements IWriter {
public void writer (String s){
System.out.println("The string is " + s);
}
}
Another class
package DI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
#Service
public class MySpringBeanWithDependency {
#Autowired
private IWriter writer;
#Autowired
private IWriter niceWriter
public void run() {
String s = "This is my test";
writer.writer(s);
}
}
I'd like to show one more option using application.properties.
Benefits:
You don't need to change code when you add/change implementation of the interface
Works well with unit tests and other environments
Sample code based on #ConditionalOnProperty attribute
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
#Service
#ConditionalOnProperty(value = "writer.type", havingValue = "default")
public class Writer implements IWriter {
#Override
public void writer(String s) {
System.out.println("The string is " + s);
}
}
And
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
#Service
#ConditionalOnProperty(value = "writer.type", havingValue = "nice")
public class NiceWriter implements IWriter {
#Override
public void writer(String s) {
System.out.println("Nice string is " + s);
}
}
When application.properties contains writer.type=nice NiceWriter will be instantiated for IWriter interface.
Instead of #ConditionalOnProperty there are other options like Conditional, #ConditionalOnExpression.
It depends on the use-case, you can select implementation of the interface using spring profiles, custom annotations or as mentioned by other answers using #Qualifier (injection by name) which is equivalent to JSR-330's #Named annotation

Categories

Resources