Juergen Hoeller on the Past and Future of Spring

Recorded at:

Bio Juergen Hoeller is co-founder of the Spring framework and has been the most active Spring developer since the open source project began from Rod's Interface21 framework back in February 2003. Juergen is an experienced consultant, with expertise in web apps, transaction management, O/R mapping technologies, and lightweight remoting.

Sponsored Content

SpringOne 2GX is a collocated event covering the entire Spring ecosystem and Groovy/Grails technologies.
SpringOne 2GX is a one-of-a-kind conference for application developers, solution architects, web operations and IT teams who develop, deploy and manage business applications. This is the most important Java event of 2010, especially for anyone using Spring technologies, Groovy & Grails, or Tomcat. Whether you're building and running mission-critical business applications or designing the next killer cloud application, SpringOne 2GX will keep you up to date with the latest enterprise technology.

I’ve been involved for a long time (it feels like ages), I’ve been co-founding the project back in early 2003, more than 7 and half years ago and I’ve been serving as the Spring Framework project lead basically since mid 2003. I’m guiding the Spring Framework through the ages and I’m still basically in the position of moving Spring Framework along, evolving it into a programming model well positioned for all the requirements that are coming our way, in 2012. That’s my mission at the moment.

Spring certainly was created as an alternative to the programming models of day in 2003. That was a time when we had EJB 2.0, that generation; we had Struts at the time, Struts 1.1 it would be, roughly. So we had this initial crop of frameworks at the time, but there was a feeling that we could do a better job, that a programming model needs to be more comprehensive, not like single layer web frameworks, not single layer service frameworks either. We wanted to create a more unified programming model for architectures not as strictly layered, where you get a more unified feel to the overall architecture.

That proved to be a quite successful model, we basically had an initial adoption, certainly very strongly in the J2EE JAVA, the Java EE world. But we always had a strong angle outside of the traditional J2EE umbrella as well, standalone applications, batch applications, batch processing applications, Swing applications, at the time, and of course, a very strong position in the Tomcat space as the framework of choice, pretty soon it was the framework of choice for the more sophisticated kind of web applications that you would build for deployment of Tomcat.

Spring has quite some history in the mean time. It’s code base, basically, the early days of the code base would be 2001 onwards as a public project, 2003 onwards and it has seen three generations, three major generations anyway, of the Framework, Spring 1.0 came out in March 2004 and Spring 2.0 a couple of years later, in 2006. Actually, Spring 2.5 was a pretty important generation in its own right because it introduced a lot of the annotation-based component model that we are still working with today, that we are still improving on today and Spring 3.0 of course came out in late 2009 and is the generation of the present day basically.

We, at the moment, are preparing for Spring 3.1 so the foundation that we are working with at the moment will be Spring 3 for the foreseeable future. We actually evolved Spring without a clear vision of how many generations this would really take. So, we are pretty agile in our choices and even our major generations, are actually highly backwards compatible, so we never really used the major version number as a chance to redo everything. Some frameworks do, but we made a conscious decision that the upgrade path between major generations was just as important as between the minor generations.

And that’s why, basically, if you happen to have an application being built against Spring 1.2 it will actually run just fine against 3.0. At least there’s a 99% chance that it will. So the evolution of Spring has been, I would say, like a careful evolving from minor generation to minor generation, major generation to major generation. There was never really ever evolution in terms of the framework’s code base, of the framework’s own architecture. It’s basically the same foundational architecture as in 2003. It just saw a careful revisions over time, adopting pretty revolutionary features basically onto an evolutionary code base underneath.

So this balance that we are trying to achieve where we present the very modern programming model, these days, in annotation based component model in particular, while, at the same time, also catering to the audience and to the basic architecture that we had originally. I think that balance is actually something that characterizes Spring pretty well.

Spring 3.0, to some degree, completed a mission that we started in Spring 2.5. In Spring 2.5 we really started going into the annotation-based component world, much more strongly than we did before. We did so against the Spring 2.0 foundation. In Spring 3.0 we basically continued that path, but we updated a lot of the core framework architecture onto a Java 5 basis. The most important step, from our own perspective, in Spring 3.0 certainly was that we went through the entire code base and updated it to the Java 5 level, using Java 5 APIs, using Generics and Varargs. Also revisiting all the user level APIs, making good use of Generics and Varargs for example.

That’s not really the user level feature set for a start. It was just an important foundational step for us to take and on top of that we added new facilities like the expression parser, the Spring expression language and a couple of other foundational features, for example the conversion service facility; a couple of interesting programming model features that came in, for example the enhanced stereotype model where we have this notion of a stereotype annotation, which in Spring 3.0 is now a composable feature where a custom stereotype annotation may be composed from standard stereotypes, transactional characteristics, and a default scope, and you’re basically wrapping this up in custom stereotype and, as a shortcut, this combines the semantics of the underlying standard stereotype, the default transactional semantics and the scope.

There are a couple of really interesting improvements to the annotation based component model that proved to be very useful for translating an architecture onto the framework basically. The, probably, most important addition to the component model world is what we call "configuration classes" these days. It used to be called Spring Java Config. This is basically a model, an annotation based factory method model with some really interesting characteristics in how you compose configuration classes with several factory methods.

This wasn’t really a brand new feature. It used to be in the Spring Java Config Project, but it has been re-implemented in Spring 3.0 and it became a core part, inherent part of the framework, very well aligned with the rest of the core annotation component model. That was a pretty important goal of ours: to provide a comprehensive annotation model that really has intuitive semantics when combining several of the annotation based features. On a completely different front (well, not quite that different maybe) Spring 3 also had a REST theme. So we took Spring MVC and added RESTful capabilities in many places: first class REST support, so that any kind of RESTful architecture translates onto a Spring MVC web layer very nicely.

We also have client side REST support in the form of REST template for example. So those would be some of the most important feature themes. One further area of notice certainly is the support for standard annotations. So Spring 3.0 supports JSR 330 that would the dependency injection for Java. Spring implements the JSR 330 capabilities natively and passes the TCK. It’s actually, I suppose, the mainstream implementation of the JSR 330 today. That’s the concrete annotations are @inject, @qualifier and @provider interface -very important common annotations for the use in service classes expressing common dependency injection characteristics.

It certainly is very much part of Spring’s mission to keep supporting standard annotations where they fit very nicely into the Spring world. It started with annotations like @PostConstruct and @PreDestroy back in Spring 2.5 and JSR 330 and the @inject model is basically the next step that we are taking towards a standardized annotation-based component model, from our perspective.

We have a tendency to start the more experimental kind of feature as a separate project, basically. So separate projects, to some degree, just start as a bit more of an R&D effort, but we don’t really know how far we are going to take this basically. With Java Config is actually a good example where Java Config really evolved over several milestones so it really had to go through several feedback cycles in order to become a mature arrangement and the addition to Spring Framework was primarily driven by demand.

We had quite a few people asking for the Java Config model to become a first class citizen in the Spring world next to the XML Bean definition model and adding it to Spring framework seemed like a very reasonable thing to do from that perspective, but also from a technical perspective. Integrating features into the core allows us to have a unified implementation, to share as much of the implementation as possible with related features in the Spring core and that’s basically the second kind of characteristic.

If there is a chance of achieving a better more unified implementation, that alone is often a reason while we are adding features to the core and to the present day we still run quite a number of sister projects, separate projects. Another concern, of course, is the life cycle of those projects, the release cycle of those projects. If a project intends to evolve very quickly, have many releases, have major releases, more often than the Spring framework core would, then again might be a reason why a project remains separate and Web Flow is, for example, primarily for that kind of reason, a separate project because it has a life of its own and major releases of its own.

Web Flow also has, of course, many characteristics that really characterize it as a standalone product, a project of its own, with some Flow definition language and Flow definition model. It’s somewhere in between those characteristics we try to make the best possible decision in terms of whether a project should remain separate or is a candidate for inclusion in the core.

Spring 3.1 is part of our general 3.x plan. With Spring 3.0 we established a foundation where we already have couple of features planned basically, already had them right from the start, that we knew we’d made 3.0 for timing reasons and a selection of those features is what Spring 3.1 will be now. Some of those features are, for example, the environment profiles for bean definitions where there’s first class support for associating a set of bean definitions with a specific environment profile, beans that it will only be active if the profile is active and that’s a very useful mechanism.

It proves to be useful for many kinds of scenarios where traditionally development, testing, production would be different profiles, but also different deployment arrangements where for different databases, target databases, or target message brokers you would have different profiles. Part of that model is also the notion of more flexible place-holder resolution where property place-holders, a well-known Spring concept, can be sourced from different places now where they could still be system properties, but we allow for environmental property sources.

So there could be JNDI attributes, JNDI variables, could be context programs in Web XML. There are different sources that we just provide a more first class model for it now. That’s one major theme that we are having, another is the cache abstraction. So, for a long time we intended to do a cache abstraction. There is an org.springframework.cache package, dates back to 2004-2005 maybe, but it used to be empty with two EHCache factory beans. We are filling that package now, so the cache abstraction is a longtime favorite of ours. We’ve always wanted to do it and now we’re finally doing it in a form that’s driven by very current demand with the rise of Cloud platforms.

With that rise of Cloud platforms comes the rise of distributed caching and distributed caching with a first class user cache access model basically. Our cache abstraction is not only a cache manager abstraction, it comes with a rich set of caching annotations that allow for declarative putting into the cache, declarative access to the cache, declarative eviction from the cache, computing the cache key from the method signature and taking the return value as the cached value. So, it’s quite a rich arrangement that we are coming up now and this arrangement will probably be available in the very first milestone and it’s full incarnation already.

Another area of investment in Spring 3.1 is conversation management. We’re researching many options. Conversation management is, on the one hand, a web oriented feature, but on the other hand, conversation management is also pretty useful in messaging scenarios where the notion of a conversation is quite different. But there is a common characteristic where conversations will be identified by, and there is the notion of a current conversation for currently executing request, so a lot of those common characteristics will be expressed in the form of common APIs in the Spring core. This also serves as a foundation for the upcoming Web Flow 3 release.

So, it’s a good example of a feature that makes it into Spring Framework. If there is a common ground to be established where different parts of the Framework ecosystem need to communicate with each other, then this is what we typically add to Spring Framework and the conversation abstraction is exactly that kind of feature.

There is certainly a relationship between different projects at the moment where some of those form a bigger picture and Spring Data is a good example where the focus on non-relational data source joins very nicely into modern distributed caches. Because, if you take a product like GemFire, it can serve as a distributed cache, but it’s fundamentally a data store of sorts, so we are trying to not only use or allow access in the form of a cache. In the Spring Data Project we actually take those data stores as basically a replacement for your traditional relational database.

And we use established Spring data access principles, like template classes, exception translation and provide adaptors for common non-relational data stores such as neo4J or Redis. We are basically at the moment of time in Enterprise Java, where a lot of alternative trends are in the process of finding their place, their position in the market. We are at the forefront of taking the most interesting products in the space and just making them first-class citizens in the Spring world, allowing convenient access to them from Spring-based applications.

So both the cache abstraction effort and the Spring data effort are certainly part of that mission where we are trying to allow for the same level of convenience that people are used to when working against JDBC or working against Hibernate. The same level of convenience is what we aim to provide for non-relational data stores and for distributed caches.

JEE6 is a revision of the EE standard that we have been tracking for a long time. So we were following EE6 basically since its inception and part of the 3.0 feature set or 3.0 goals, the Spring 3.0 goals, was to provide compatibility with Java EE6 runtimes, Java EE6 servers, basically, as a platform that you deploy Spring-based applications onto. But also to adopt a selection of specifications from the EE6 umbrella, for example Java persistence API 2.0, Java server faces 2.0, and, in particular, the JSR-303 bean validation specifications and making them a first class citizens in the Spring programming model.

With Spring 3.0 we immediately shipped JPA 2.0 support for the spring JPA support and we had JSR-303 support both for standalone setup of a validation provider and for declarative access into Spring MVC. We improve on that story in Spring 3.1 by going even further with Servlet 3.0, with Tomcat 7 now approaching production quality towards the end of this year we intend to have first class support for Servlet in 3.0. We’re still in the process of researching how far we’re going to take this. Runtime compatibility is actually something that Spring 3.0 already manages to provide with the Servlet 3.0 container as the target, but there are some interesting features in Servlet 3 that we may have first class support for in Spring MVC in particular.

Auto-deployment of framework components might be an area, but this notion of asynchronous request processing, suspending requests and resuming them in another thread is also something where we are researching what Spring MVC can do in order to expose those facilities when using Spring MVC on a Servelt 3.0 container. JEE6 overall is certainly an important factor that we take into account when both designing the Spring feature set and also in terms of runtime compatibility. At this point GlassFish 3 would be the Java EE6 server that we typically test against.

It’s the only production ready Java EE6 server at this point and we have even an explicit GlassFish 3 support, for example for Load-Time Weaving on GlassFish. So Spring 3 on GlassFish 3 is actually quite a nice combination that we typically use as an example for how Spring and Java EE6 may interact and co-exist very nicely. It’s a best of both worlds arrangement that we are aiming for. Of course, at the same time, we have alternative trends in the market where platforms like Google App Engine go quite a different way. They are basically reducing the platform specifications to the absolute minimum where you have basically the core APIs from Java SE, a servlet container, typical servlet 2.5 level, and a JPA for access to the data store. No more than that.

At the same time, Spring is also a very good citizen, in this kind of a world. On a platform like Google App Engine where we have to live with a more minimal set of standard middleware underneath, where Spring basically takes what it gets and makes good use of it and it turns out that Spring is actually a pretty popular choice on Google App Engine as well. We collaborate with Google on improving that story even further. So Spring is really driven from very different requirements. These are interesting times in that respect. Platforms are even more diverse than they used to be and the Java EE standard platform will certainly establish itself in the market.

But at the same time Cloud deployment platforms are unlikely to adopt as extensive a set of platform specifications, but we see this reduction trend certainly continuing for platform-as-a-service offerings like Google App Engine.

Spring has a tradition of avoiding dependencies on a very specific runtime platform. The original driver, back at the time, was to bridge the differences between a Servelt container like Tomcat or Jetty, on the one hand, and a JEE server on the other hand where just the commonalities are obvious, the Servlet container in particular, JNDI look ups for data sources, maybe, but the differences are, of course, as obvious, in transaction management or when embedding a message broker, when embedding a persistence provider. These differences are something that we’ve learned to live with.

The Framework is very capable of taking the middleware foundation that it gets and linking it to the application components in a very straightforward fashion. So we strive for a balance where we are not trying to hide the underlying platform, we are trying to expose as much as possible for immediate consumption in the application’s code base in the Spring style. This usually means that you are actually building an application where if you know that you are deploying to a very rich middleware platform, you’re trying to make good use of all of those facilities through just some tweaks in configuration and in resource look up in centralized parts of the Spring configuration.

You can adapt basically the same kind of application onto a more minimalistic deployment platform and you would embed a couple of providers with the application. For example, if you take GlassFish 3, JPA provider, a Bean validation provider, all of those come with the server. You don’t need to embed those in the application. On Google App Engine, on the other hand, well you do get a JPA provider, but if you want to use Bean validation you need to include a Bean validation provider just as a JAR file and Spring is very capable of adapting to both of those scenarios, it’s the framework of choice for Cloud platforms, primarily for that reason, for that flexibility, and, at the same time, it makes a lot of sense to use it on Java EE6 as well.

So we have a track record of adapting to those kinds of differences; this is well understood within the Spring community as well. For most of the Spring users this is a very natural thing to do, moving between different environments and shipping some embedded providers into one case but not in the other and adapting Spring configuration accordingly.

Java 7 indeed took a long time, and it’s been changed, several features, the source level features, in particular are moving to Java 8, but Java 7 arriving mid next year is actually something that Spring audience should look forward to from my perspective, because Java 7 has several interesting runtime features for us. In the Spring based world the choice of the VM level that you are deploying to is often quite flexible, so for a certain class of applications like standalone batch processing applications, integration applications, message driven applications, we do actually expect that people will be able to upgrade to Java 7 quite eagerly, if they choose to do so.

For that reason, Spring 3.2 released after the next minor generation, after 3.1, is actually expected to come with quite rich Java SE 7 support. So the idea is that if you ‘re running on Java 7, Spring as a framework will expose as much Java 7 specific functionality as possible for consumption in application code. There are several interesting features that we will catch up with from JDBC 4.1 to possibly support for the try with resources clause, the auto-closeable interface. So there are several core facilities, but probably the most important addition to Java 7 at the API level is the Fork/Join framework, an addition to java. util.concurrent where there is first-class support for implementing asynchronous work units in the form of recursive actions.

The basic idea is that processing steps, in particular CPU intensive processing steps are being decomposed into smaller units, like an incoming text file that need to be parsed could be segmented into smaller chunks and those chunks could be processed concurrently in several threads so the action would fork into smaller tasks and in order to get the result at the very end they would be joined into the full result at the very end. This kind of programming pattern is turning into a first class programming pattern in the Java 7 world, the Fork/Join pool, Fork/Join tasks and recursive actions form central pieces of API where users basically get a bit of guidance, get a bit of infrastructure in how to implement tasks that allow for this kind of scaling.

At the same time, Java 7 will deliver a very highly optimized Fork/Join pool implementation. So this is basically what we will be getting. From a Spring Framework perspective we can quite easily expose a Fork/Join pool management, so configuration of a Fork/Join pool, the lifecycle of a Fork/Join pool, and also injection of the Fork/Join pool references into components, application components that intend to use Fork/Join tasks. All of these are services that the Spring framework can very easily provide. Just like it does at the moment, like a regular executor services, regular Runables, Callables, for standard java. util.concurrent.

The same kind of runtime support we will be offering for the Fork/Join Framework. Personally, I’m expecting this to become very relevant as we move to servers with even more cores where we will actually reach a situation where for some kinds of system the number of concurrent requests, of incoming requests, will by no means be high enough to actually make full use of the available cores. In particular for non-public, internal systems within an enterprise it then becomes a challenge to actually make good use of those processors, of those cores and this is exactly what the Fork/Join framework addresses. It will require a bit of rethinking in terms of how we implement our processing in particular.

This is something we certainly will adapt to, not only from the Spring Framework’s technical story, but also from the recommendations, the blueprints that we are giving, so this is something that will show up in several places in the Spring ecosystem. I, for example, also expect Spring batch to be able to make some good use of those facilities when running on Java 7 whether there is some first class or declarative support building on the Fork/Join facility underneath. So there is some interesting stuff coming our way in Java 7 and I’m definitely looking forward to exposing this to our Spring user audience.