Chapter 2. New & Noteworthy in 1.0.0.m3

2.1. AnnotationApplicationContext deprecated

AnnotationApplicationContext presented a naming conflict with Spring 2.5's Annotation-Driven Configuration. To avoid this problem it has been renamed to JavaConfigApplicationContext. Beyond the renaming, JavaConfigApplicationContext has several new features worth discussing. See below for details. AnnotationApplicationContext will be removed entirely in JavaConfig 1.0.0.rc1

See Section 4.3, “ JavaConfigApplicationContext

2.2. Type-safety improvements

JavaConfigApplicationContext, JavaConfigWebApplicationContext and the ConfigurationSupport base class now all expose type-safe getBean methods, allowing for looking up beans by type, rather than by name.

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

    @Bean
    public NotificationService notificationService() {
        return new NotificationServiceImpl();
    }
}

public class SimpleApp {
    public static void main(String... args) {
        JavaConfigApplicationContext context = new JavaConfigApplicationContext(AppConfig.class);

        // use the type-safe getBean method to avoid casting and string-based lookups
        TransferService transferService = context.getBean(TransferService.class);
        TransferService notificationService = context.getBean(NotificationService.class);

        // ...
    }
}

See Section 4.3.2.1, “Type-safe access” for details.

2.3. First-class support for JavaConfig in the web tier

By popular demand, a WebApplicationContext variant of JavaConfigApplicationContext has been created. This allows for seamless bootstrapping of JavaConfig bean definitions within web.xml requiring no Spring XML whatsoever.

<web-app>
    <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- Configure ContextLoaderListener to use JavaConfigWebApplicationContext
         instead of the default XmlWebApplicationContext -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.config.java.JavaConfigWebApplicationContext</param-value>
    </context-param>
    <!-- Configuration locations must consist of one or more comma- or space-delimited
         fully-qualified @Configuration classes -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>example.RootApplicationConfig</param-value>
    </context-param>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>test</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Configure DispatcherServlet to use JavaConfigWebApplicationContext
             instead of the default XmlWebApplicationContext -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.config.java.JavaConfigWebApplicationContext</param-value>
        </init-param>
        <!-- Again, config locations must consist of one or more comma- or space-delimited
             and fully-qualified @Configuration classes -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.web.WebBeansConfig</param-value>
        </init-param>
    </servlet>
</web-app>

For basic information regarding initialization parameters to DispatcherServlet and use of ContextLoaderListener, see Chapter 13. Web MVC framework in the Core Spring Framework documentation.

For complete details on using JavaConfig in the web tier, see Chapter 7, Developing web applications with JavaConfig.

2.4. New semantics for nested @Configuration classes

Consider the case of nested @Configuration classes:

@Configuration
public class OuterConfig {
    @Bean
    public Foo outerBean() {
        // ...
    }
}

@Configuration
public static class InnerConfig {
    @Bean
    public Bar innerBean() {
        // ...
    }
}

In previous milestones, any nested @Configuration classes (such as InnerConfig above) were treated as just another source of bean definitions and were processed inline with the rest of the beans in the declaring @Configuration class. Ultimately, all bean definitions ended up in the same BeanFactory/ApplicationContext.

Now and going forward, nested @Configuration classes will be processed as child ApplicationContexts. Perhaps better said, any declaring (outer) @Configuration classes will be processed as parent ApplicationContexts. Using the example above, Instantiate an ApplicationContext using InnerConfig as an argument

JavaConfigApplicationContext context = new JavaConfigApplicationContext(InnerConfig.class);
context.getBean("innerBean"); // locally defined beans are available
context.getBean("outerBean"); // as are beans defined in the declaring OuterConfig class.

Note that when supplying OuterConfig as the argument, InnerConfig is ignored entirely. If it were to be processed, it would become a child context, but its beans would would be inaccessible (parent contexts have no access to child context beans).

JavaConfigApplicationContext context = new JavaConfigApplicationContext(OuterConfig.class);
context.getBean("outerBean"); // works fine
context.getBean("innerBean"); // throws NoSuchBeanDefinitionException!

See Section 5.6, “Nesting @Configuration classes” for full details.

2.5. Modularization improvements with @Import

JavaConfig now has the equivalent of XML configuration's <import/> element. One configuration class can import any number of other configuration classes, and their bean definitions will be processed as if locally defined.

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(...);
    }
}

@Configuration
@Import(DataSourceConfig.class)
public class AppConfig extends ConfigurationSupport {
    @Bean
    public void TransferService transferService() {
        return new TransferServiceImpl(getBean(DataSource.class);
    }
}

Importing multiple configurations can be done by supplying an array of classes to the @Import annotation

@Configuration
@Import({ DataSourceConfig.class, TransactionConfig.class })
public class AppConfig extends ConfigurationSupport {
    // bean definitions here can reference bean definitions in DataSourceConfig or TransactionConfig
}

See ??? for full details.

2.6. Support for externalizing string values with @ExternalValue

Important: This functionality may change!. We are currently evaluating approaches for best supporting externalized values. See SJC-74 for more details.

Somewhat similar to the way that @ExternalBean makes it possible to reference beans defined outside of the current @Configuration, @ExternalBean allows for accessing externalized string values in properties files. This is ideal for use when configuring up infrastructural resources with properties that may change at deployment time, or otherwise need to be externally accessible for modification.

@Configuration
@ResourceBundles("classpath:/com/myapp/datasource")
public abstract class AppConfig {
    @Bean
    public DataSource myDataSource() {
        DataSource dataSource = new MyDataSource();
        dataSource.setUsername(username());
        dataSource.setPassword(password());
        dataSource.setUrl(url());

        return dataSource;
    }

    @ExternalValue
    public abstract String username();

    @ExternalValue
    public abstract String password();

    @ExternalValue("jdbc.url")
    public abstract String url();
}

com/myapp/datasource.properties:

username=scott
password=tiger
jdbc.url=...

See Section 5.5, “Externalizing values with @ExternalValue and @ResourceBundles for full details