Though there are ways to explicitly wire dependencies by using Spring XML configuration or Spring JavaConfig but Spring also provides automatic configuration where beans are detected automatically using component scanning and dependencies are wired automatically using Autowiring. In this post we'll see a Spring example program using component scan for auto detection of beans and autowiring of dependencies.
Two things you need to know for automatic configuration in Spring are-
- Component scanning- Spring does the work of automatically discovering the beans to be created
in the application context rather than you explicitly defining them. It is done using the annotation
@Component
(and some other variants of it like@Service
,@Repository
,@Controller
or any custom annotation that itself is annotated with @Component). - Autowiring- Spring does the work of automatically detecting and wiring the dependencies.
In this tutorial Maven is used to create a general Java project structure.
- Refer Creating a Maven project in Eclipse to know more about how to create project structure using Maven.
Technologies used
- Spring 5.0.4
- JDK 1.8
- Apache Maven 3.3.3
- Eclipse IDE
Spring @ComponentScan annotation example step by step
Provide dependencies in pom.xml of Maven
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.netjs.exp</groupId> <artifactId>Spring-Example</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Spring-Example</name> <url>http://maven.apache.org</url> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>5.0.4.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </project>
Note that you'll already have most of the entries in pom.xml, you just need to add dependencies for spring-core and spring-context and an entry for spring.version in properties element. Spring-context is needed for the annotations.
Spring @ComponentScan annotation example - Java classes
We need 2 classes PaymentService and CashPayment. Since Spring promotes loose coupling so it is always recommended to code to interfaces. So we'll also create interfaces for the classes.
Payment Service
public interface IPayService { void performPayment(); }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PayServiceImpl implements IPayService { @Autowired private IPayment payment; public void performPayment() { payment.executePayment(); } public IPayment getPayment() { return payment; } public void setPayment(IPayment payment) { this.payment = payment; } }
Here note that the class is annotated with @Service annotation, that's how it is made sure that this class is discovered while a component scan is done. Also note that the dependency to the payment is annotated with the annotation @Autowired. That's how Spring will automatically detect this dependency and inject it.
Cash Payment
public interface IPayment { void executePayment(); }
import org.springframework.stereotype.Component; @Component public class CashPayment implements IPayment{ public void executePayment() { System.out.println("Perform Cash Payment - "); } }
Spring Configuration for component scanning
For Spring component scanning configuration we can use either a Java class or XML configuration. Both the configurations are shown here.
If you are using XML configuration then you need to use context:component-scan tag with base-package. I have created Java classes in the package org.netjs.prog so that's what I'll give as the base package. Spring framework will automatically scan that package for components.
<?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"> <context:component-scan base-package="org.netjs.prog" /> </beans>
Notice the addition of new name space.
xmlns:context="http://www.springframework.org/schema/context"
This is required because we are using context:component-scan.
If you are using Spring Java configuration then you just need this-
@Configuration @ComponentScan(basePackages="org.netjs.prog") public class AppConfig { }
You can annotate a Java class with
@ComponentScan
and provide the package which is to be scanned withbasePackage attribute
. You don't need to provide any code with in the class.Java class to run the application
If you are using XML configuration then the Java class to run the application will be like this -
public class App { public static void main( String[] args ){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("appcontext.xml"); IPayService bean = (IPayService) context.getBean("payServiceImpl"); bean.performPayment(); context.close(); } }
Here appcontext.xml is the name of the XML file created above.
If you are using Java class then the class to run the application will be like this -
public class App { public static void main( String[] args ){ AbstractApplicationContext context = new AnnotationConfigApplicationContext (AppConfig.class); IPayService bean = (IPayService) context.getBean("payServiceImpl"); bean.performPayment(); context.close(); } }
Here note that AnnotationConfigApplicationContext is used to create the Spring application context which takes the JavaConfig class as input.
NoUniqueBeanDefinitionException with Spring autowiring
In the above application we had used only one implementation of IPayment, CashPayment so there was no problem in automatically wiring it. Now suppose we have one more implementation of the IPayment interface, Credit Payment. In that case with the current setup you'll get NoUniqueBeanDefinitionException
because Spring won't know which Payment class to wire.
For these types of scenarios where ambiguity is there Spring provides an option of using @Qualifier
annotation
to qualify the bean.
Spring autowiring with @Qualifier annotation to qualify bean
CreditPayment class
@Component public class CreditPayment implements IPayment { public void executePayment() { System.out.println("Performing credit payment "); } }
Since we have two classes implementing IPayment interface now; CashPayment and CreditPayment, so we need to make changes in the PayServiceImpl class and use the qualifier annotation to wire the dependency. If we need CreditPayment class to be wired then PayServiceImpl class will look like this.
@Service public class PayServiceImpl implements IPayService { @Autowired @Qualifier("creditPayment") private IPayment payment; public void performPayment() { payment.executePayment(); } public IPayment getPayment() { return payment; } public void setPayment(IPayment payment) { this.payment = payment; } }
Note the Qualifier annotation used with the payment reference.
That's all for this topic Spring Component Scan Example - Auto Detect Bean and AutoWiring. If you have any doubt or any suggestions to make please drop a comment. Thanks!
>>>Return to Spring Tutorial Page
Related Topics
You may also like-
No comments:
Post a Comment