Chapter 2. Components

Java Configuration uses annotations to leverage Java constructs allowing beans to be created and configured by the developer without leaving the Java world. In short, the developer will instantiate and configure the beans through Java code and then instruct the container to use them. Before moving forward, please note that the Spring semantics remain the same no matter how the configuration takes place: Java or XML.

Let's look at the most important annotations on which JavaConfig relies:

2.1. @Configuration

The @Configuration annotation indicates configuration classes:

@Configuration
public class WebConfiguration {
   // bean definitions follow
}

@Configuration is a class (type) level annotation and indicates the defaults for the bean definitions definied by the configuration:

@Configuration(defaultAutowire = Autowire.BY_TYPE, defaultLazy = Lazy.FALSE)
public class DataSourceConfiguration 
     extends ConfigurationSupport {
}

It can be considered the equivalent of <beans/> tag. It is advisable that classes with @Configuration annotation extend the ConfigurationSupport as it offers several utility methods.

2.2. @Bean

As the name implies, @Bean indicates a bean definition (the <bean/> tag). Let's start with a simple example:

@Bean (scope = DefaultScopes.SESSION)
public ExampleBean exampleBean() {
  return new ExampleBean();
}

The code above instructed the Spring container to create a bean using the method name (as bean name) and return value (for the actual bean instance). The bean has session scope, which means the exampleBean() method will be called to create a new bean instance per HTTP session.

Since pure Java is used, there is no need to use:

- factory-method when dealing with static methods:

@Bean
public ExampleBean exampleBean() {
  return ExampleFactory.createBean();
}

or

- FactoryBean/MethodInvokingFactoryBean for complex object creation:

@Bean(aliases = { "anniversaries" })
public List<Date> birthdays() {
  List<Date> dates = new ArrayList<Date>();
  Calendar calendar = Calendar.getInstance();

  calendar.set(1977, 05, 28);
  dates.add(calendar.getTime());
  dates.add(computeMotherInLawBirthday());

  return dates;
}

@Bean is a method level annotation and indicates the Java code used for creating and configuring a bean instance. The annotation supports most of the options offered by an XML bean definition such as autowiring, lazy-init, dependency-check, depends-on and scoping. Also, the lifecycle methods and *Aware interfaces are fully supported:

public class AwareBean implements BeanFactoryAware {

  private BeanFactory factory;

  // BeanFactoryAware setter
  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
   this.factory = beanFactory;
  }

  public void close(){
    // do clean-up
  }
}
@Bean(destroyMethodName = "close", lazy = Lazy.TRUE)
public AwareBean createBeanFactoryAwareBean() {
   return new AwareBean();
}

Besides destroyMethodName, @Bean annotation supports also initMethodName though its usage is discourage as one already has control over the object creation and thus can call the initializing method if needed.

2.3. @ExternalBean

@ExternalBean is a simple markup annotation used for injecting 'external' beans, defined in a parent application context. Let's look at example:

@Configuration
public abstract class ExternalBeanConfiguration {
  @Bean
  public TestBean james() {
    TestBean james = new TestBean();
    // inject dependency from ann()
    james.setSpouse(ann());
    return james;
  }

  // Will be taken from the parent context
  @ExternalBean
  public abstract TestBean ann();
}

When JavaConfig encounter @ExternalBean, it will override the owning method so that anytime the method is being called, the parent application context will be looked for the bean under the method name (please see the naming chapter for more details). This way, your configuration remains pure Java and refactoring friendly.

Note that @ExternalBean works on normal method also; the example above uses the abstract method to avoid writing dummy code that doesn't execute:

@Configuration
public class ExternalBeanOnNormalMethod {

  @ExternalBean
  public TestBean ann(){
      System.out.println("this code will not execute as the method " +
          "will be overriden with a bean look up at runtime");
  }
}

2.4. @ScopedProxy

Spring offers a convenient way of working with scoped dependencies through scoped proxies(please see the link for an in-depth discussion on the matter). The easiest way to create such a proxy, when using the XML configuration, is the <aop:scoped-proxy/> element. JavaConfig offers as alternative the @ScopedProxy annotation which provides the same semantic and configuration options.

The reference documentation XML scoped proxy example, looks like this under JavaConfig:

// a HTTP Session-scoped bean exposed as a proxy
@Bean(scope = DefaultScopes.SESSION)
@ScopedProxy
public UserPreferences userPreferences() {
   return new UserPreferences();
}

@Bean
public Service userService() {
   UserService service = new SimpleUserService();
   // a reference to the proxied 'userPreferences' bean
   service.seUserPreferences(userPreferences());
   return service;
}