Last week I was at the Danish Spring User Group meetup in Copenhagen where I did a presentation on the new features in Spring 3.0. About 20 were present, but I thought it might be interesting to read about also.
Generally, Spring 3.0 does not contain any revolutionary features that will change the way you do enterprise development, but there are a number of nice new features which can make Spring easier and nicer to use. I should also note that everything I write is based on Spring 3.0 M4, where some features are still missing, and there might be a number of bugs.
General changes
Generally, support for JDK 1.4 is being removed, so most features will not be usable unless you use JDK 5. Also, support for JUnit 3 is deprecated, meaning that the good old AbstractDependencyInjectionContextTests is not to be used. Instead, use the testrunner introduced in 2.5 together with JUnit 4.
In many places, varargs and generics have been introduced - this is primarily in the ApplicationContext interface, but other places too. Some interfaces, however, will not be changed, so check out the new API.
Most of Spring's own dependencies will be upgraded. This shouldn't be much of a problem, but look out for this if you actually use any of the libraries (for example from Apache Commons).
Changes in Spring Beans
In Spring 2.5, there were two common ways of declaring Spring beans: using the standard XML and/or using annotations and autowiring. Spring 3.0 introduces a new way of declaring beans, namely the JavaConfig API.
Using the JavaConfig API, it is possible to declare beans in pure Java. It is not a complete XML replacement, as the JavaConfig classes will still need to be declared as Spring beans, and for that you need XML, at the very least component scanning.
A quick example on declaring beans:
CODE:
-
@Configuration
-
public class SpringConfig {
-
-
@Bean
-
public MessageGenerator messageGenerator() {
-
return new EchoMessageGenerator();
-
}
-
-
@Bean
-
public AsyncMessageGenerator asyncGenerator() {
-
return new AsyncMessageGenerator(messagePrinter());
-
}
-
-
@Bean
-
public MessagePrinter messagePrinter() {
-
return new MessagePrinter();
-
}
-
}
@Configuration is a @Component, so component scanning will pick up the configuration class. Basically, @Configuration corresponds to the <beans> tag in XML, and each method annotated with @Bean corresponds to the <bean> tag. In the example above, 3 beans are declared: messageGenerator of type MessageGenerator, asyncGenerator of type AsyncMessageGenerator, and messagePrinter of type MessagePrinter. Notice how asyncGenerator has a dependency which is injected using constructor injection by simply calling the bean method. Of course, bean names can be configured using the @Bean annotations. Also, beans can be marked as lazy using the new @Lazy annotation.
Due to technicalities about CGLIB, configuration classes cannot be final and they must have a no-arg constructor. This is because even though, as in the example above, messagePrinter() will be invoked twice, the actual instance will only be invoked once, thereby keeping the singleton scope for beans, which is still the default.
So why would you want to use JavaConfig? Frankly, I'm not sure - especially because you still have to use the old XML files. JavaConfig might be nice for type safety - when you refactor classes and methods, these changes will be picked up by the compiler. Time will tell if this will actually be useful.
Besides the new configuration API, there are some smaller changes which are relevant when declaring beans:
- It is now possible to autowire scalar values into a bean. This happens using a combination of a new @Value annotation and PropertyPlaceHolders. On a bean property set for example @Value("{db.url}"), and declare that property in a properties file and load that file using a PropertyPlaceHolder. Spring will then inject the property value into the bean. Using this, it is often possible to avoid any XML declarations at all.
- More annotations to complement XML configuration: @Lazy to mark a bean as lazy, @DependsOn to express a dependency, and @Primary to mark the primary autowiring candidate.
- Finally there's a new type conversion infrastructure, which supercedes the old PropertyEditors. PropertyEditors are stateful and somewhat cumbersome to implement. The new converters are thread-safe and simple to implement. The old PropertyEditors are still supported.
There are a number of smaller changes also in the beans xml schema, but I've not experimented with them.
Threading and Scheduling
Here we actually have some pretty nice new features. Basically, Spring 3.0 supports the java.util.concurrent package introduced in JDK 5. Earlier, the new features could be used in Spring, but you had to configure a Executor yourself, schedule jobs, and so on (of course, it was still much better than using the classical synchronized/wait/notifyAll approach). However, Spring 3.0 improves this with two new annotations, @Async and @Scheduled, a number of support classes, and a new namespace.
Async scheduling is used when you want to execute a job in a thread, and at some point you might want a result. In Spring 3.0, it would look something like this:
CODE:
-
public class AsyncMessageGenerator {
-
@Async
-
public Future<String> getMessage(String message) {
-
try {
-
Thread.sleep(10000);
-
} catch (InterruptedException e) {
-
throw new RuntimeException(e);
-
}
-
return new AsyncResult<String>(message);
-
}
-
}
Using this looks something like this:
CODE:
-
public class AsyncMessageGeneratorTest {
-
@Autowired private AsyncMessageGenerator generator;
-
-
public void testGetMessage() throws InterruptedException, ExecutionException {
-
Future<String> res = generator.getMessage("test"));
-
// do work
-
System.out.println(res.get());
-
}
-
}
Spring will detect the @Async annotation and wrap the bean in an AOP Proxy, which will then execute the method in a standard Executor thread. The Future object is a standard java.util.concurrent.Future object, which you can block on if you want to wait for the thread to complete. Any method annotated with @Async must return either void or Future. When returning future, use the AsyncResult class from Spring to wrap the result in the implementation.
As usual, Spring will not do this by pure magic, so you need to register a BeanPostProcessor. Luckily, this can be done using the new scheduling namespace:
CODE:
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:task="http://www.springframework.org/schema/task"
-
xsi:schemaLocation="http://www.springframework.org/schema/beans
-
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
-
http://www.springframework.org/schema/task
-
http://www.springframework.org/schema/task/spring-task-3.0.xsd
-
">
-
-
<context:annotation-config />
-
<task:annotation-driven />
-
</beans>
This will register the appropriate BeanPostProcessors, and it will also configure a new Executor. If the default configuration is not ok, it can be customized using the executor element in the annotation-driven tag.
The second way of using threading is by using the @Scheduled annotation. Use this if you want to do something like a TimerTask where a job should be run periodically. The annotation can be used on any void method like this:
CODE:
-
public class MessagePrinter {
-
private int num;
-
-
@Scheduled(fixedRate=1000)
-
public void printMessage() {
-
System.out.println("Message number " + ++num);
-
}
-
}
The method shouldn't be called manually, as Spring will pick it up automatically when instructed to do so using the task:annotation-driven element. In this example, the printMessage method will be run every second. For more advanced scheduling, the annotation also supports the cron attribute which makes it possible to schedule according to regular cron expressions.
These two annotations cover most of the usual scheduling cases, and I think they're a great addition to Spring 3.0.
REST Support
Support for REST services is probably one of the more known features about Spring 3.0. The REST support is not revolutionary, and personally I prefer JAX-RS, but if you are already using Spring @MVC, using Spring REST might make sense. At least it's simple to use.
Spring REST consists of two parts: A client API for accessing REST services, and a number of new annotations for @MVC for implementing REST services. The client API is centered around a new RestTemplate, which like all the other Template classes encapsulates all resource management and any transformations you'd want to make, for example from JSON to typed objects.
Using the RestTemplate, you can issue GET/PUT/DELETE/POST requests against a url. It looks something like this:
CODE:
-
public class RestClient {
-
public List<Conference> listConferences() {
-
RestTemplate rt = new RestTemplate();
-
rt.setMessageConverters(new HttpMessageConverter[] {
-
new MappingJacksonHttpMessageConverter<Object>()
-
});
-
Conference[] res = rt.getForObject("http://jaoo.dk/jaoorest/json", Conference[].class);
-
-
return Arrays.asList(res);
-
}
-
}
In this example, a GET request is issued against http://jaoo.dk/jaoorest/json. This returns a JSON representation, which is mapped to a regular POJO using the MappingJacksonHttpMessageConverter. This converter simply maps a JSON field to a bean property without any further configuration. For more complicated cases, the raw requests and responses can be accessed using callback methods on the RestTemplate - again like using any other Template class in Spring.
Developing REST services is simply a question of using Spring @MVC and a couple of new annotations. Here's an example:
CODE:
-
@Controller
-
public class RestService {
-
-
@Autowired
-
private RestClient client;
-
-
@RequestMapping(value="/{user}", method=RequestMethod.GET)
-
public void listFiles(@PathVariable("user") String user, @RequestHeader("ETag") String etag) {
-
// if etag matches return NOT_MODIFIED
-
-
System.out.println("Getting files for " + user);
-
}
-
-
@RequestMapping(value="/{user}", method=RequestMethod.PUT)
-
public void createFile(@PathVariable("user") String user, @RequestBody InputStream is) {
-
// write data to file
-
}
-
-
@RequestMapping("/")
-
public ModelAndView getFeed() {
-
ModelAndView mv = new ModelAndView();
-
-
List<Conference> cs = client.listConferences();
-
mv.setView(new ConferenceFeedView());
-
mv.addObject("conferences", cs);
-
-
return mv;
-
}
-
}
The @RequestMapping annotation is used as in 2.5, but now it also supports templates using {name}. A url can then be split into parts like "/blog/{year}/{month}/{day}/{item}", and each of these parts can be bound to a method parameter using the @PathVariable annotation. This means no more manual url parsing.
This is probably the main feature, but there are also a couple of other annotations:
- @RequestHeader can be used to bind a request header to a method parameter with automatic type conversion. Headers can be marked as required or can have a default value.
- @CookieValue can bind a cookie to a method parameter
- @RequestBody can bind the body of the request to a method parameter
- @ExceptionHandler can be used to handle certain types of exception using other views than the default error view
Finally, there are a couple of new view implementations for generating feeds: the AbstractAtomFeedView and the AbstractRssFeedView.
There are some other minor additions to @MVC, but I haven't had time to look into them.
Support for embedded databases
Many people have had the need for an embedded database, especially when running tests, and especially when using an ORM like Hibernate. Previously, you had to start one yourself, probably in some abstract test class, which all test classes then extended. In Spring 3.0, however, Spring can take care of that for you. This happens using the new jdbc namespace, like this:
CODE:
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
-
xsi:schemaLocation="http://www.springframework.org/schema/beans
-
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
-
http://www.springframework.org/schema/jdbc
-
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
-
">
-
-
<jdbc:embedded-database id="embedded-datasource" type="HSQL">
-
<jdbc:script location="classpath:embed.sql" />
-
</jdbc:embedded-database>
-
</beans>
This will automatically create a new DataSource called "embedded-datasource" using HSQL, and after starting the database, it will automatically load the SQL script in embed.sql from the classpath.
Real simple, and it can remove some of your template code, which is always nice.
Spring Expression Language
A new module in Spring 3.0 is the Spring Expression Language. It's somewhat like the existing expression languages such as JSTL, OGNL, and so on, just with some additional features. Why? Good question, but Spring EL does have some nice features, and Spring EL will be used as the unified EL across all Spring modules. Whether it's worth the effort or not, I can't say.
Spring EL expressions are placed in #{}, and can be used in bean XML declarations when setting properties or referring to beans. Here are some examples:
CODE:
-
#{bean.messages} // access a property on the object named "bean"
-
#{new java.io.File(bean.path)} // create a new instance of java.io.File
-
#{T(String).format('%s', bean.message)} // invoke a static method on the String class (note the usage of the T operator)
-
#{props['jdbc.url']} // access a property in the Properties object named "props"
-
#{bean?.inner?.prop} // navigate safely through a chain, avoiding any NPEs
-
#{users.?[active == true]} // select all objects where the active property is true from the collection named "users"
There are many other features, this is just a short sample. Of course you can also use SpEL outside Spring, but that's a little more complicated.
Model Validation
Spring 3.0 will support JSR-303 declarative model validation when it becomes final. The M4 release does not have any validation code yet, but that should arrive with the release candidate. Because of this, I haven't had the opportunity to examine it closer.
Release schedule
Accoring to SpringSource, RC1 should be out this week. RC1 will be feature complete and with updated documentation. The reference documentation is already pretty uptodate, and the Javadocs also.
After RC1, the3.0GA (General Availability) release should be around October, but that depends on the amount of feedback from the community. Finally, 3.1 should be out in early 2010 - no major features are planned yet, but all new features from JEE6 should be supported - probably @Inject, JSR-303 final, and so on.
That's it for now. As I've already mentioned, there are numerous smaller changes and bugfixes, so check out the bug tracker if you're interested in something particular.