J3 Limited
 
Google
WWW J3Ltd
 
Introduction to Spring

Spring Annotations

So far the example code has used an application context defined in an xml file. This file contains the definitions for the Spring beans.

Spring offers the ability to use annotations instead of an xml configuration file. It is also possible to use both an xml file and annotations.

The Java Community Process has come up with dependency injection annotations (searching for jsr-330 and jsr-250 on the internet provides abundant information on this topic). Hence, there is more than one annotation to achieve the same goal, for example Spring's @Autowired compares well to the standards based @Inject.

From a Spring tutorial's point of view, it is worth mentioning here that there is more than one dependency injection dialect available. However to keep this article brief, only Spring's annotations are covered.

Introduction to Spring Annotations

Spring provides several annotations for managing beans:

@Configuration
@Bean
@DependsOn
@Primary
@Lazy
@Import
@ImportResource
@Value
@Component
@Service
@Repository
@Autowired


And many more.

@Bean, @Component, @Service and @Repository are used to define beans that reside in the context. The different names are used to represent the use for which a bean was designed:

  • @Repository typically represents datasource information.
  • @Service usually denotes a class with methods to perform operations.
  • @Bean identifies a Spring bean which holds data.
  • @Component is a Spring bean that is not really a Service or a Repository.

@Configuration is a special annotation that is used to define the application's Spring beans and configures the Spring application context, in effect it replaces the xml configuration file.

Pure Annotation Project

In this section a new project is developed, that does the same thing as the previous projects: output text to the console. Two printer classes are used to output text to the console. DevelopmentPrinter represents a printer for the development team, ProductionPrinter represents a printer class for the live environment.

The difference is that the project does not use an xml application context. Everything is achieved using Spring's annotations.

An new Java project is created, called SpringConsoleAnnotation. A folder called lib is created to hold the jar library files, and a res folder is created to hold a properties file, as shown below:

It is worth making noting:

  1. That the correct library jar files are added. In addition to those used in previous projects, org.springframework.aop-3.1.1.RELEASE.jar is added.
  2. That the res folder is added to the project's sources build path.

SpringConsole.properties File

A new file is created in the res folder, called SpringConsole.properties

SpringConsole.properties
printer=devPrint
printer.scope=prototype

This file is used to hold environment differences between a production (live) setup and a development setup. The printer property holds the bean name to use, the printer.scope defines the bean scope to use for the bean. In this way a development environment can use a different Spring bean than the production environment.

Annotation Configuration Class

A new class called SpringConfig is created. This class replaces the xml configuration used in preceding sections.

SpringConfig.java
package springtutorial;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@Configuration
@PropertySource("classpath:SpringConsole.properties")
@ComponentScan("springtutorial")
public class SpringConfig {
	private @Autowired ApplicationContext ctx;
	@Value("${printer}")
	private String printerBeanName = "";
	
	@Bean
	@Scope("${printer.scope}")
	public IPrinter print() {
	
		return (IPrinter) ctx.getBean(printerBeanName);
	}

	@Bean
public IMain mainApp() {
Main main = ctx.getBean(Main.class);
main.setSpringWiredProperty("value set in SpringConfig");

return main;
} @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
  • The class is annotated with @Configuration to inform the Spring framework that this class configures the application context.
  • @PropertySource("classpath:SpringConsole.properties") A Java property file is used for runtime configuration: configures which printer class to use.
  • @ComponentScan("springtutorial") informs Spring which packages to scan for Spring annotated beans. Beans found are automatically wired up and loaded up into the Application's context.
  • @Autowired ApplicationContext ctx; in order to retrieve beans from Spring's application context, it is necessary to have a copy of the context instance. This line wires it up for us.
  • @Value("${printer}")refers to a property in the property file, called printer. The value is read and stored in the printerBeanName local variable.
  • The first @Bean injects a new IPrinter bean into the application context. Its scope is read from the property ${printer.scope}, the bean's name takes the method name print. The method body retrieves the bean from Spring's application context with the line return (IPrinter) ctx.getBean(printerBeanName);
  • The second @Bean injects a new IMain bean called mainApp. The method body retrieves the Main type bean from the context, and sets a property value on it (main.setSpringWiredProperty("value set in SpringConfig");).
  • Finally a bean PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() is defined to allow property file support to be used in this Spring Configuration bean.

Main Class

Below is the Main class, this is the class that is run as an application. It is also annotated as a Spring Service bean.

Main.java
package springtutorial;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class Main implements IMain {
	private String springWiredProperty;
	private @Autowired IPrinter print;
	private @Autowired ApplicationContext ctx;
	
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
		context.scan("springtutorial");
		IMain mainApp = (IMain) context.getBean("mainApp");
		mainApp.go();
	}

	@Override
	public void go() {
		print.print("It works " + springWiredProperty);
		print.print("a second line");
		
		IPrinter print2 = (IPrinter) ctx.getBean("print");
		print2.print("print from second printer bean");
	}

	public String getSpringWiredProperty() {
		return springWiredProperty;
	}

	public void setSpringWiredProperty(String springWiredProperty) {
		this.springWiredProperty = springWiredProperty;
	}
}
  • The class is annotated with @Service.
  • @Autowired properties are added, one property is called print, the other ctx. Spring tries to find beans matching the name, and if that fails, the type, and sets the properties automatically for us.
  • In the main() method, a new context of type AnnotationConfigApplicationContext is created. It takes as an argument the class that is to be used as the application context, SpringConfig described in the previous section. Spring is told to look for annotated beans in the springtutorial package with the line context.scan("springtutorial");.
  • The go() method gets a second "print" bean from the context to illustrate that the prototype copy of the bean defined in SpringConfig works.

Printer Classes

The printer classes are annotated with @Service(beanName)

DevelopmentPrinter.java
package springtutorial;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service("devPrint")
@Scope("prototype")
public class DevelopmentPrinter implements IPrinter {
	private int lineNumber;
	
	@Override
	public void print(String line) {
		System.out.print("Development["+ lineNumber++ +"]: ");
		System.out.println(line);		
	}

}
  • The Spring service is given the name devPrint
  • The class is annotated with the prototype scope.
ProductionPrinter.java
package springtutorial;

import org.springframework.stereotype.Service;

@Service("prodPrint")
public class ProductionPrinter implements IPrinter {

	@Override
	public void print(String line) {
		System.out.print("Production: ");
		System.out.println(line);		
	}

}
  • The Spring service is given the name prodPrint

Java Interfaces

The interfaces referenced by the Main, DevelopmentPrinter and ProductionPrinter are written.

IMain.java
package springtutorial;

public interface IMain {
	public void go();
}

A printer interface, called IPrinter, is created.

IPrinter.java
package springtutorial;

public interface IPrinter {
	public void print(String line);
}

 

Run the Application

Main is run as a Java application, and the console output is shown below:

Development[0]: It works value set in SpringConfig
Development[1]: a second line
Development[0]: print from second printer bean

The source code for this project can be found here.

Conclusion

This completes the application as a pure Spring annotation project. The features available in the previous, xml Spring configuration, are reproduced here using Java and Spring annotations.

In the marketplace, most Spring based projects tend to be a hybrid: a mixture of annotations and xml based configuration. The next section takes this project and converts it into a hybrid solution.

 

 

  Copyright © 2006 J3 Ltd Permission is granted to reproduce material on this page, on the condition that a reference to "WWW.J3Ltd.com" is given as the source of the material.