Monday, 12 October 2015

Spring example program using JavaConfig and Annotations

In this post I'll talk about how to create a Spring example program using JavaConfig. 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 JavaConfig.

  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.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>
        <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>3.8.1</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();
    }
    
    public class PayServiceImpl implements IPayService {
     private IPayment payment;
     
     public void performPayment() {
      payment.executePayment();
     }
     
     public IPayment getPayment() {
      return payment;
     }
    
     
     public void setPayment(IPayment payment) {
      this.payment = payment;
     }
    }
    

    Cash Payment

    public interface IPayment {
     void executePayment();
    }
    
    public class CashPayment implements IPayment{
     public void executePayment() {
      System.out.println("Perform Cash Payment "); 
     }
    }
    
  3. Create JavaConfig class

    To create JavaConfig class you need to annotate it with @Configuration. When a class is annotated with @Configuration annotation the annotated class is identified as a configuration class. This configuration class will contain the @Bean annotated methods, these methods will provide details about the beans that are to be created and managed by the Spring application context.

    It's better to keep config classes in a separate package so create a new package and create the config class (I have named it AppConfig.java) there.

    package org.netjs.exp.config;
    
    import org.netjs.exp.Spring_Example.CashPayment;
    import org.netjs.exp.Spring_Example.IPayService;
    import org.netjs.exp.Spring_Example.IPayment;
    import org.netjs.exp.Spring_Example.PayServiceImpl;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AppConfig {
     @Bean
     public IPayService payService(){
      PayServiceImpl payServiceImpl = new PayServiceImpl();
      payServiceImpl.setPayment(cashPayment());
      return payServiceImpl;
     }
     
     @Bean
     public IPayment cashPayment(){
      return new CashPayment(); 
     }
    }
    

    Here it can be seen how the methods that create the beans are annotated with @Bean annotation. Also note that in this configuration class I have given example of setter based dependency injection.

  4. Java class to run the application

    package org.netjs.exp.Spring_Example;
    
    import org.netjs.exp.config.AppConfig;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.AbstractApplicationContext;
    
    public class App 
    {
        public static void main( String[] args ){
         AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            IPayService bean = (IPayService) context.getBean("payService");
            bean.performPayment();
            context.close();
        }
    }
    

    Here note that AnnotationConfigApplicationContext is used to create the Spring application context. It takes the JavaConfig class as input and search for all the beans in the configuration class by looking for the methods annotated with @Bean annotation.
    Another thing to note that is, by default the bean's id is the same as the name given to the method annotated with @Bean. That's why you can get the PayService bean using -

    context.getBean("payService");
    
    Because in the JavaConfig class method's name is payService. If you want to provide another name then you can use the name attribute. As example if you want to call the payService bean as myPayService then it can be done this way -
    @Bean(name="myPayService")
    public IPayService payService(){
     PayServiceImpl payServiceImpl = new PayServiceImpl();
     payServiceImpl.setPayment(cashPayment());
     return payServiceImpl;
    }
    
    And then it should be called as
     
    IPayService bean = (IPayService) context.getBean("myPayService");
    

As I mentioned above, the configuration done was for setter. If you want to use constructor dependency injection then you need to change it a little.

Suppose the PayService class is like this -
 
public class PayServiceImpl implements IPayService {
 
 private IPayment payment;
 public PayServiceImpl(IPayment payment){
  this.payment = payment;
 }
 
 public void performPayment() {
  payment.executePayment();
 }

}
Then in JavaConfig class we have to provide a constructor injection.
package org.netjs.exp.config;

import org.netjs.exp.Spring_Example.CashPayment;
import org.netjs.exp.Spring_Example.IPayService;
import org.netjs.exp.Spring_Example.IPayment;
import org.netjs.exp.Spring_Example.PayServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
 @Bean
 public IPayService payService(){
  return new PayServiceImpl(cashPayment());
 }
 
 @Bean
 public IPayment cashPayment(){
  return new CashPayment(); 
 }
}

That's all for this topic Spring example program using JavaConfig. 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 automatic configuration
  3. What is Dependency Injection in Spring
  4. Dependency Injection using factory-method in Spring
  5. Bean definition inheritance in Spring
  6. Data access in Spring framework

You may also like -

>>>Go to Spring tutorial page

No comments:

Post a Comment