Monday, 19 October 2015

Spring example program using automatic configuration

Though there are ways to explicitly wire dependencies by using Spring XML configuration or Spring JavaConfig but Spring also provides automatic configuration. Two things you need to know for automatic configuration 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.

Technologies used

  • Spring 4.2.1
  • JDK 1.8
  • Apache Maven 3.3.3
  • Eclipse Luna 4.2.2

 In this Spring program there are 2 classes; first is Payment Service and another is Cash Payment class, let's go step by step to see how these classes are created and configured using Spring automatic configuration.

  1. 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.prog</groupId>
      <artifactId>maven-spring</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>maven-spring</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.2.1.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.

  2. Create 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();
    }
    
    @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();
    }
    
    @Component
    public class CashPayment implements IPayment{
     public void executePayment() {
      System.out.println("Perform Cash Payment - ");
      
     }
    }
    
  3. Confguration class

    For automatic configuration we can use either a Java class or XML configuration. I'll show both the way here.

    If you are using XML configuration then you need to use context:component-scan 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.

    <?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-4.0.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 Java class 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 with basePackage attribute. You don't need to provide any code with in the class.

  4. 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.

No Unique bean definition Exception

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 couple of options. One of them is using @Qualifier annotation to qualify the bean.

Code for CreditPayment class

@Component
public class CreditPayment implements IPayment {
 public void executePayment() {
  System.out.println("Performing credit payment ");

 }

}

Since we have two classes now, implementing IPayment interface 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 example program using automatic configuration. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring example program using XML configuration
  2. Spring example program using JavaConfig and Annotations
  3. What is Dependency Injection in Spring
  4. Autowiring using annotations in Spring
  5. Autodiscovery of bean using componenent-scan in Spring
  6. Different bean scopes in Spring

You may also like -

>>>Go to Spring tutorial page

No comments:

Post a Comment