A Java configuration option for Spring

Thanks to our philosophy of pluggability and a lot of hard work in the implementation, the Spring IoC container (like most of the rest of Spring) is extremely flexible.
One point that is often missed is that Spring configuration need not be in XML, although the XML format is by far the most commonly used. Spring has its own internal metadata format in the form of the BeanDefinition interface and subinterfaces. The BeanFactory and ApplicationContext implementations that represent IoC container instances are powered by this Java metadata, and are quite separate from metadata parsing, which is normally performed by BeanDefinitionReader implementations.
The BeanDefinition metadata was not originally designed with the end developer in view. With Spring 2.0, NamespaceHandlers (classes that handle XML extension namespaces) generate BeanDefinition metadata, and we introduced the BeanDefinitionBuilder, with a fluent API to make this easier. But generating BeanDefinition metadata nevertheless remains in the realm of infrastructure coding, rather than something to do daily as you code business logic and define regular Spring beans.
Today I want to describe a new option for defining beans in Java code, which is targeted to end users (developers) rather than infrastructure providers. This is currently a milestone release add-on to the Spring core, but may make its way into Spring proper.
Let start with an example:
public class MyConfig {
@Bean
public Person rod() {
return new Person("Rod Johnson");
}
@Bean(scope = Scope.PROTOTYPE)
public Book book() {
Book book = new Book("Expert One-on-One J2EE Design and Development");
book.setAuthor(rod()); // rod() method is actually a bean reference !
return book;
}
}
The @Configuration annotation identifies this object as a special configuration class. Each @Bean method defines a bean. The name of the bean is the name of the method. It's possible to define additional aliases with the annotation, but its best to pick up the name from the method, rather than the annotation, as it means that the compiler can take care of ensuring ambiguity.
Beans are configured in Java code, using constructors, properties or arbitrary method calls. Note that a call to another bean method establishes a dependency from the "book" bean to the "rod" bean. But there are key advantages over instantiating objects in Java without framework support: for example:
- Every @Bean is a Spring component and can take advantage of all Spring services, such as declarative transaction management
- Every public @Bean method is added to the Spring container, so it's eligible for injection into other objects, JMX export and other benefits.
- It fits smoothly into an existing Spring environment.
It may be easier to follow what is happening by comparing this with XML definitions to achieve the same result, which would look as follows:
<constructor-arg>Rod Johnson</constructor-arg>
</bean>
<bean id="book" class="Book" scope="prototype">
<constructor-arg>Expert One-on-One J2EE Design and Development</constructor-arg>
<property name="author" ref="rod"/>
</bean>
Although it is based on annotations, this Java config mechanism is unique in uses of annotations I've seen that annotations are not included in the core business logic, but in separate configuration classes. Effectively, it's a DSL for configuration. So it retains the non-invasive promise of Spring: you don't need to change your Java code to use it.
The configuration class is analogous to an XML bean definition file, and thus the @Configuration annotation contains some similar options to the the <beans> element, such as default autowire or lazy init. For example:
public class DataSourceConfiguration extends ConfigurationSupport {
}
The @Bean annotation allows options such as scope, and lazy init to be set locally, just as with the <bean> element. The default scope is Singleton, as with XML.
This style of Java configuration has some interesting characteristics. For example:
- References (such as the reference to the "rod" bean in the example) survive refactoring; any good IDE provides great tool support.
- Because configurations are Java classes, they can participate in inheritance relationships. For example, you could define a superclass that demands some abstract @Beans to be implemented in subclasses.
- It creates a new visibility option. An @Bean method can be protected, it which case it benefits from the usual characteristics of the Spring component, but is not visible externally–that is it not injectable and cannot be obtained by calling getBean() on the IoC context.
My experience in showing this to people (for over a year now) is that they sometimes take a moment to grok it, but usually end up quite enthusiastic.
This is not intended as a replacement for Spring's XML format. Like Spring 2.0 extension namespaces–and use of properties files which has been possible since Spring 1.0–it's an additional option. Complex applications require multiple types of configuration and Spring aims to provide the best overall solution for configuration. We continue to explore additional forms of configuration.
You will typically mix use of Java and XML configuration. You can use any number of Java configuration classes in the same application context.
The following example uses an XML bean definition to define a MyConfig bean, as shown above, which can be injected like any normal bean. The ConfigurationPostProcessor processes all beans with @Configuration annotations, generating the necessary bean definitions.
<bean class="..MyConfig"/>
<bean class="org.springframework.beans.factory.java.ConfigurationPostProcessor"/>
<bean class="SomeRandomBean">
<property…
</bean>
</beans>
You can of course have plain old bean definitions, like "SomeRandomBean" in this example, in the same XML. And you could build a context out of Java configuration and existing XML configurations.
Costin has also implemented a convenient application context that uses wildcarding to load classes from the classpath like this:
ApplicationContext aBunchOfConfigs = new AnnotationApplicationContext("**/configuration/*Configuration.class");
Classes are examined using ASM, without loading them. In future releases we'll probably offer additional autodetection scenarios.
The release is here. Costin Leau is now the project lead. The code should be considered alpha quality. We include an example of a modified Spring Pet Store, but lessons will undoubtedly be learned from use on real projects.
Costin and I would love your feedback on this feature.
What will happen to this code? Well, it depends on you. It certainly needs feedback (suggestions welcome), and the full range of possibilities (and implementation refinements) will emerge through use in anger, with any technology. It's not currently on the roadmap, but could make its way into a future version of the Spring core if it sparks enough interest.
Also, it needs a snappy name. Suggestions welcome!
Although today is the first (alpha) release, this functionality has a surprisingly long history–well over a year. I had a mad fit of coding when attending a software summit in Crested Butte, Colorado in August 2005, with Mark Pollack and Aleks Seovic of the Spring.NET project. I remember writing a lot of code in the back of a Jaguar XJ8 while Aleks drove from the Great Sand Dunes to Denver. I probably needed to write code to take my mind off the danger. I think the genesis of the idea may have actually dated back to a conversation with Howard Lewis Ship at JavaOne 2005…
Sadly I haven't had time to do more than work on this in fits and starts since, so hadn't gotten it to the point where we could release it. Fortunately, Costin Leau, Spring Modules lead and general Spring guru, has had more time for Spring coding since he joined Interface21 early this year, and he's stepped up to take this forward.
The implementation doesn't require any modifications to the Spring core. As I said, the IoC container is highly flexible. In case you're interested, it treats the configuration object as a factory bean and each bean definition is backed by an instance factory method on that object: A mechanism that has been available since Spring 1.1. It does a little bytecode manipulation on the configuration instance, presently using CGLIB, to make sure that repeated calls to singleton scoped @Bean methods always return the same object.
Eugene Kuleshov says:
Added on November 28th, 2006 at 7:31 pm -QuoteCool stuff! Although very similar features were possible with jacn for a while [1].
Anyways, can you or Costin write up a paragraph about usage of ASM in Spring Framework for ASM's users page? [2]
[1] http://jacn.sourceforge.net/
[2] http://asm.objectweb.org/users.html
Karl Moore says:
Added on November 29th, 2006 at 3:55 am -QuoteThis looks like a very interesting feature. I've seen people on the forums asking for this so it should be well received. I'm quite intrigued to see how people intend to use this. I appreciate this isn't a replacement for XML, but people can be quite polar about things like this. Interesting to see if people do go for a hyrid approach.
The characteristics of Java configuration does raise some interesting points, specifically visibility. Can you do this in XML configured Spring (again seen it raised on the forums)?
As for a name, Spring XJ8 - "Unleash the Jaguar in you"
Graeme Rocher says:
Added on November 29th, 2006 at 4:35 am -QuoteHey Rod,
Looks pretty neat. As a Groovy alternative checkout Grails' new BeanBuilder that is coming in Grails 0.4: http://grails.org/Spring Bean Builder
It is kind of a Spring DSL for creating bean definitions and supports all of what the XML version offers unless I've missed something
Comments welcome!
Cheers,
Graeme
Graeme Rocher says:
Added on November 29th, 2006 at 4:37 am -QuoteHmm link didn't work too well. Retry: http://grails.org/Spring Bean Builder
Rodrigo Urubatan says:
Added on November 29th, 2006 at 6:09 am -QuoteHi,
It is almost the reason I started Spring-Annotation project (https://spring-annotation.dev.java.net/nonav/);
Today night I`ll release the version 1.0.2 that will use the XML Schema option of spring 2.0 to enable the annotations reading (instead of another ApplicationContext implementation as the previous version).
if you do not like the Spring-Annotation approach, you can at lease use the same same kind of XML Schema configuration to enable your annotation approach.
look at one of the test cases:
import net.java.dev.springannotation.annotation.Property;
public class ParentBean {
@Property(bean="scopeTest")
private ScopeTestBean testProp;
public ScopeTestBean getTestProp() {
return testProp;
}
public void setTestProp(ScopeTestBean testProp) {
this.testProp = testProp;
}
}
import net.java.dev.springannotation.annotation.Bean;
@Bean(name="parentTest")
public class ParentPropertyBean extends ParentBean{
}
package net.java.dev.springannotation.annotation;
import net.java.dev.springannotation.annotation.beans.ParentPropertyBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase;
public class ParentPropertyTest extends TestCase {
private ApplicationContext factory;
protected void setUp() throws Exception {
factory = new ClassPathXmlApplicationContext("classpath*:testContext.xml");
}
public void testParentProperty() {
ParentPropertyBean bean = (ParentPropertyBean) factory.getBean("parentTest");
assertNotNull(bean.getTestProp());
}
}
– the XML configuration –
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sa="https://spring-annotation.dev.java.net/context"
xsi:schemaLocation="https://spring-annotation.dev.java.net/context https://spring-annotation.dev.java.net/nonav/context.xsd"
default-autowire="byName">
<sa:annotation-autoload/>
</beans>
I almost never use the @Property annotation, I prefer to just use the auto-wire approach …
We have a lot of good code already written, the support for JSF is great and you have two more scopes already implemented for JSF applications (working in port it to Spring MVC).
flash (from the end of one request to the start of the next one)
and conversation (until a method with @ConvEnd is executed)
please take a look and comment.
Guillaume Poirier says:
Added on November 29th, 2006 at 8:21 am -QuoteI absolutely love the idea, I sometimes feel the need to have conditional logic in the xml configuration files, that solves that problem nicely. That fills the need I saw lacking in scripting support for configuration, I thought what was missing was the possibility to create your own bean and add them to the spring context. You annotation does that and goes even further.
I have one question though, is it possible to get beans from the xml context injected in the annotation context? If so, what's he API to access that context, an abstract method annotated?
Christian Dupuis says:
Added on November 29th, 2006 at 1:17 pm -QuoteHi Guillaume.
Yes that is indeed possible. Have a look at 'Chapter 4. Mixing XML and annotations' of the reference documentation. It comes down to calling ConfigurationSupport.getBean(beanName).
Rick Hightower says:
Added on November 29th, 2006 at 2:55 pm -QuoteRod,
Where I've seen Spring adoption retarded was around percieved need for "mass amount of XML configuration" with annotation being the new soup du jour. I've recieved a lot of feedback from customers who don't like the XML configuration (many end up living with it to get the other benefits of Spring). This is a great new tool. Thanks.
Personally, I find the Spring XML configuration acceptable and not very error prone given the Spring IDE support and code completion (and when you compare to XML config for JSF, EJB, etc. it is extremely light). Yet….
I know this is a feature I would use (and possible prefer over XML). If you combine this feature with the new Spring 2.0 sytle annoations for AOP, you could almost reduce the amount of XML configuration to nothing for a typical application.
Have you looked at Spring Annotations? It is very Seam-ish and seems to provide another way to avoid "mass amounts of XML configuration".
When will this support be in the core?
When will "Spring Annotation" support be in the core?
–Rick Hightower
Rick Hightower says:
Added on November 29th, 2006 at 3:08 pm -QuoteRodrigo,
Great stuff!
I looked into Spring Annotations after your post on TSS. I think Spring Annotations is one of the most innovative new features of Spring (or would be if it was in the official project). I just wish it was in the core. (I have not used it in anger yet so will withhold final judgement till I can bleed with it for a while.)
I was shocked to see the cool reception you received from some of the Spring guys (okay just one) on TSS.
I think your focus on providing Seam style support for Spring makes a lot of sense and is exactly what some of my customers have been looking for.
I like the philosophy behind Spring Annotations, i.e., keeping simple things simple and not needing a lot of configuration.
I am not sure I agree with all of the decisions (I am not sure I don't agree either). The docs seems a bit weak compared to what is available for Seam and Spring.
There is still a lot to explore wrt to Spring Annotations. For example, can I override an annotation with an entry in the Spring app context file?
–Rick Hightower
Rodrigo Urubatan says:
Added on November 29th, 2006 at 3:50 pm -QuoteRick,
there is plenty of room for changes in the project yet, and your opinion will be very welcome,
in the today version (1.0.2) there is no way to override the annotations with XML, I`m researching a way to do this, but I want it included in the 1.1 version, this is a very important feature.
I would thank you a lot if you could take a look at the few examples and docs in the site and contribute with some ideas.
and I agree that there is too litle documentation today, I`m looking for help on this, but I have wrote a litle more docs and published it today.
G. says:
Added on November 30th, 2006 at 3:46 am -QuoteNice stuff. It opens the door to many possibilities.
I like the idea to keep the configuration stuff outside of the pojos. Also it makes refactoring easier and this is cool.
It reminds me the code of the ServiceLocator I used to implement
Does this mean that you can add conditionnal code inside these Config classes. Isn't it a door left open to lots of hacky, unclean practices? Which is the exact contrary to the Spring spirit. (as in #configure in c/c , but here i am just tryin ti guess , as i do not know c/c … yes it is not good i know..)
Another possibility could be to have theses config file replaced by some groovy code - which means a compromise between xml and java - with the advantages of dynamic languages, more possibilities to have loops or conditions, and yet something outside the code ie that can be tuned at deployment time/runtime.
Rod Johnson (blog author) says:
Added on November 30th, 2006 at 5:56 am -QuoteI don't think that having conditional code inside this config classes would be hacky. Programming in XML is bad, but programming in Java is fine. I think that where you want conditional logic is probably an indication to use this approach.
Yes, a Groovy option certainly makes sense.
Piotr Gabryanczyk says:
Added on November 30th, 2006 at 6:00 am -QuoteThis feature will solve the following problems:
1. Too complex XML files can be replaced with simple factory classes. BTW. You could easly adopt your existing factories to function as spring contexts! This is cool! As a consequence most of the configuration simply disappears (someone already mentioned it…)
2. If you need control over configuration, you don't have to use ( ugly in my opinion) bean factories, which where not intuitive - you can not be sure what the bean factory produces without looking at it's source. Also they seem to be seen as Spring-specific mechanism making your app strongly dependent on spring framework, which give me this strange feeling(smell) that it is one step too far.
Personally I was fine with XML config files, but this feature will make developing Spring applications even easier!
Rod Johnson (blog author) says:
Added on November 30th, 2006 at 6:10 am -QuotePiotr, I think you are spot on regarding the fact that this handles a number of scenarios very elegantly. For example, if you want to call arbitrary methods (not setters, constructors or init methods) with arguments that are injected or computed:
public class AConfiguration {
private Dependency1 dep1; // Setter omitted
private Dependency2 dep2; // Setter omitted
private Dependency2 dep2; // Setter omitted
@Bean
public SomeBean someBean() {
SomeBean sb = new SomeBean();
sb.callArbitraryMethod(dep1, dep2, System.currentTimeMillis());
return sb;
}
}
Regarding 2, I assume you mean FactoryBeans? Yes, this mechanism should solve some of the same problems. As you can dependency inject the @Configuration classes you can easily satisfy any dependencies you may need to populate the returned object.
Rod Johnson (blog author) says:
Added on November 30th, 2006 at 6:12 am -QuoteOops, I accidentally submitted that and don't believe I can edit it. The code sample was incomplete. It should read:
public class AConfiguration {
private Dependency1 dep1; // Setter omitted
private Dependency2 dep2; // Setter omitted
private Dependency3 dep3; // Setter omitted
@Bean
public SomeBean someBean() {
SomeBean sb = new SomeBean(dep1);
sb.callArbitraryMethod(dep2, dep3, System.currentTimeMillis());
return sb;
}
}
Costin Leau says:
Added on November 30th, 2006 at 9:10 am -QuoteOn November 30, 2006 at 3:46 am, G. said:
Scripting languages make a lot of sense. I tried plugging Groovy but unfortunately annotations are not yet supported by the Groovy compiler which means the metadata has to be read/stored differently.
Graeme Rocher says:
Added on November 30th, 2006 at 9:51 am -QuoteOn November 30, 2006 at 9:10 am, Costin Leau said:
Scripting languages make a lot of sense. I tried plugging Groovy but unfortunately annotations are not yet supported by the Groovy compiler which means the metadata has to be read/stored differently.
My last message was disregarded as spam by the blog, maybe because I tried to post a tiny URL, but yes annotations are not supported by Groovy atm. However, they are not needed because of Groovy's meta programming model.
Here is a snippet from the Grails runtime configuration engine that configures Spring Hibernate using a Groovy-Spring DSL:
hibProps."hibernate.hbm2ddl.auto" = "create-drop"
}
else if(dataSource.dbCreate) {
hibProps."hibernate.hbm2ddl.auto" = dataSource.dbCreate
}
sessionFactory(ConfigurableLocalSessionFactoryBean) {
dataSource = dataSource
if(application.classLoader.getResource("hibernate.cfg.xml")) {
configLocation = "classpath:hibernate.cfg.xml"
}
hibernateProperties = { MapToPropertiesFactoryBean b ->
map = hibProps
}
grailsApplication = ref("grailsApplication", true)
classLoader = classLoader
}
transactionManager(HibernateTransactionManager) {
sessionFactory = sessionFactory
}
The method names translate to bean definition names, the first argument is the bean class. The closure at the end allows you to set properties on the bean. The full documentation can be found on the Grails website, but unfortunately the blog system here doesn't allow plus signs in URLs like those found in confluence wikis and when I post the link as a tinyurl it thinks it is spam.
If you go to http://grails.org/Spring_Bean_Builder and replace the underscores with pluses you will see the rest of the docs. It is not tied to Grails and can be used standalone or as part of another application.
Piotr Gabryanczyk says:
Added on November 30th, 2006 at 12:03 pm -QuoteCostin, I must add to that - although I like the idea of dynamic languages, it is quite natural to express the configuration in the language you are using for developent. This is the reason why I prefer java over XML in many cases. You can use refactoring, and easily reuse part of your configuration for testing, etc.
I guess languages like groovy wont find much adoption until tools start supporting them. As far as I am concerned you can not debug Groovy.
Look at AspectJ - it never really kicked off because of custom language. It has better chance now after introducing annotations. Even today I had a conversation with head of IT departament about it and he still thought it is not easy to debug AspectJ… (yes, I am proud, head of my departament still knows how to code
)
To summarize - Groovy as a configuration option yes, but not as a replacement for XML.
Rod Johnson (blog author) says:
Added on November 30th, 2006 at 12:13 pm -QuotePiotr
Indeed. These things are strengths of the Java approach.
Rod
Christian Dupuis says:
Added on November 30th, 2006 at 1:26 pm -QuoteI prototyped support for the Java configuration option as part of Spring IDE. I summarized my findings at http://springide.org/project/wiki/SpringJavaConfigurationOption.
Let me know what you think of adding this to Spring IDE once the project is final.
Christian
Rod Johnson (blog author) says:
Added on November 30th, 2006 at 1:48 pm -QuoteChristian
Wow–fast work! And I'm impressed that Spring IDE has such a solid base you can move forward so quickly…
Rgds
Rod
Jan Berkel says:
Added on November 30th, 2006 at 2:09 pm -QuoteI think a DSL implemented in a dynamic language is a viable option.
I've just implemented a JRuby-based DSL for wiring up spring contexts (Springy).
The above example could be expressed as follows:
bean :book, "Book", :scope=>"prototype" do |b|
b.new("Expert One-on-One J2EE Design and Development").author(:rod)
end
However, as Piotr pointed out, no tool or refactoring support.
Rick Hightower says:
Added on November 30th, 2006 at 2:26 pm -QuoteHmmm…. The XML file was Spring specific as well. Now you can replace that with a Java configuration class. Either way you have one artifact (n artifacts really) that is Spring specific. As long as Spring does not bleed into the rest of your app what is the issue? The only difference really is I can express the configuration in XML or Java, I am not anymore more tied to Spring than I was before.
I like the idea of expressing the configuration in Java. I can add some logic to the configuration (if needed on a limited basis). The more I think about this… the more I like it. When will it be in the core?
Steven Devijver says:
Added on November 30th, 2006 at 3:27 pm -QuoteOne thing I would like to see added is support to return multiple objects, maybe by adding a @Beans annotation. We could use that for setting up queue listeners:
@Beans
public DefaultMessageListenerContainer createQueues() {
String[] queueNames = new String[] { "queue1", "queue2", "queue3", … }
DefaultMessageListenerContainer[] listeners =
new DefaultMessageListenerContainers[queueNames.lenght];
for (int i = 0; i
For queues this approach is ok since listeners don't need to have a bean name, but maybe the project should provide a Bean class where in the constructor you can pass a name and an object (bean).
And if I look at this code, maybe is makes more sense to create a template class for similar scenarios. Another question: is support planned for reading properties, doing JNDI lookups and lookup methods?
Nice work.
Steven
Colin Sampaleanu (blog author) says:
Added on November 30th, 2006 at 4:01 pm -QuoteI have been discussing a few other things with Rod. One idea I had is to handle very basic bean definitions where all you want is to specify the class, by using an abstract method, and letting the engine implement it, e.g.:
@SimpleBean(scope = Scope.PROTOTYPE)
abstract MyServiceImpl myService();
At runtime this gets extended to return an instance of MyServiceImpl. So basically you do not have to type
{
return new MyServiceImpl();
}
and of course it's more concise, so hopefully also easier to read.
Rod also suggested this mechanism could be used to alias beans from XML or another application context, so instead of having to use a call to
ConfigurationSupport.getBean("myBean")
to get and then inject an external bean called "myBean", you add an alias to an external bean via
@ExternalBean(xxxxx)
abstract MyBean myBean();
and then to inject this just do a myBean() call. The nice thing is now you get type safety.
Colin
Christof Laenzlinger says:
Added on November 30th, 2006 at 6:46 pm -QuoteI think this is really great initiative. Especially for modularizing applications and building application components. This would allow to provide some public configuration for modules while keeping internal configuration private or protected. I missed such access control in the XML configuration.
Eugene Kuleshov says:
Added on November 30th, 2006 at 7:09 pm -QuoteChristian, definitely, go for it! Though some markers on the left bar would be really handy and I hope these beans will be automatically shown in the Spring view.
Comments are disabled in springide blog, so I hope you'll read this…
Choon Whee says:
Added on December 1st, 2006 at 1:49 am -QuoteI think this is gonna be a great addition! With emphasis of using this together with XML. Its definately is gonna make configuration a lot simpler. We could annotate stuff that are not expected to change (e.g. business services) and configure only environment dependent stuff in XML (e.g. data sources).
The best of both worlds
The only issue would probably be difficulty in locating the config (in XML or annotation)….but I guess that could quite easily be overcomed with proper organization.
Looking forward to this being added to Spring Core!
Costin Leau says:
Added on December 1st, 2006 at 3:26 am -QuoteOn November 30, 2006 at 12:03 pm, Piotr Gabryanczyk said:
You're right - scripting languages also have their downsides but they provide a simple and concise alternative to creating beans which is compelling.
Rod Johnson (blog author) says:
Added on December 1st, 2006 at 4:40 am -QuoteSteven
Interesting idea; I did consider supporting Maps at one point. It would not be easy to implement (as it's not just a factory method) but if it added sufficient value the effort would be worthwhile.
Yes. Good templates will make this very compelling, I think.
Reading properties: Need to figure out an elegant way to support it
JNDI lookups: Could be handled by a template or utility perhaps?
Lookup methods: Not required in this approach.
public void MyBean noNeedForLookupMethod() {
return new MyBean() {
@Override
public void overrideWhatYouLike() {
}
};
}
Rgds
Rod
Aaron Digulla says:
Added on December 1st, 2006 at 4:42 am -QuoteI've managed to compile the sources with maven2 but how do I run the tests?
Also, the build.xml in the subversion repository is incomplete: Many libraries (all of spring plus the deps) are missing and the properties files build and project. Can you please commit them?
Is there a mailing list for Spring JavaConfig?
Rod Johnson (blog author) says:
Added on December 1st, 2006 at 4:47 am -QuoteRick
It really depends on how many people get out there and kick the tyres and get feedback in. Once we're confident of the range of use cases and gather lessons learnt we can start to plan. It's not a huge amount of code (although the implementation is quite tricky), so there's no real obstacle to it going in the core in time.
Rgds
Rod
Costin Leau says:
Added on December 1st, 2006 at 5:10 am -QuoteOn December 1, 2006 at 4:42 am, Aaron Digulla said:
The project source code has been taken out of a private repo and there are still some loose ends (mainly the building process). I plan to take care of this in the very near future. There is a small README.TXT for the moment which indicates how the tests should be build (at the moment, some Spring test and sandbox classes are required).
As for a mailing list, I would suggest to use the Spring forums (http://forum.springframework.org/).
Jeppe Cramon says:
Added on December 1st, 2006 at 1:26 pm -QuoteVery interesting approach with a lot of flexibility. I'm glad you guys are creating Spring support for this type of configuration
The approach we've been using internally is done using a Java based DSL which looks a lot like the XML style (which people are familiar with). It's currently more limited in it's flexibility, but it makes for a straight forward transition from XML while giving you a fluent interface, code completion and refactoring support. It uses JDK 5 features and CgLib to do what it does.
We're currently working on creating aop, jee, util, etc. DSL's to get easy configuration like in Spring 2.0 XML.
Here's how a simple configuration file might look like:
@Override
public void register() throws Exception {
PropertyPlaceholderConfigurer propertyPlaceholderConfigurer = bean(PropertyPlaceholderConfigurer.class);
propertyPlaceholderConfigurer.setLocations(array(new ClassPathResource("jdbc.properties"), new ClassPathResource("other.properties")));
// ComboPooledDataSource is final
C3P0ComboPooledDataSourceWrapper dataSource = beanUsingWrapper("dataSource", ComboPooledDataSource.class, C3P0ComboPooledDataSourceWrapper.class,
lazyInit(), autoWire_No());
dataSource.setJdbcUrl("${jdbc.url}");
dataSource.setDriverClass("${jdbc.driverClassName}");
dataSource.setUser("${jdbc.username}");
dataSource.setPassword("${jdbc.password}");
destroyMethod(dataSource).close();
// Alternatively you can write attributes like this:
cfg(dataSource).lazyInit().autowire_No();
AnnotationSessionFactoryBean sessionFactoryBean = bean("sessionFactory", AnnotationSessionFactoryBean.class);
dependsOn(sessionFactoryBean, "org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect");
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setConfigLocation(new ClassPathResource("hibernate.cfg.xml"));
sessionFactoryBean.setEventListeners(
map(
entry("merge", bean(IdTransferringMergeEventListener.class))
)
);
HibernateTransactionManager transactionManager = bean("transactionManager", HibernateTransactionManager.class);
transactionManager.setSessionFactory(ref("sessionFactory", SessionFactory.class));
AnnotationTransactionAspect transactionAspect = bean("transactionAspect", AnnotationTransactionAspect.class, factoryMethod("aspectOf"));
transactionAspect.setTransactionManager(transactionManager);
}
});
GenericApplicationContext applicationContext = new GenericApplicationContext();
cfg.toApplicationContext(applicationContext);
applicationContext.refresh();
/Jeppe
Christian Dupuis says:
Added on December 1st, 2006 at 4:21 pm -QuoteEugene, thanks for your feedback.
What kind of information do you expect to get from the markers? Similiar to the approach Spring IDE uses for XML configuration files, we will not automatically detect annotated Java configuration classes right away. You can configure a specific class as a Spring IDE Config-using the preference page in the project's properties-and put it into a ConfigSet-together with other XML configuration files.
If a Java configuration class is added, Spring IDE will display the defined beans in the Beans View and the Project Navigator.
Christian
Thomas Timbul says:
Added on December 1st, 2006 at 6:04 pm -QuoteJNDI injection could be done using yet further Annotations?
@JNDI(lookup="/comp/env/myJndiObject")
public abstract MyJndiObject getIt();
And similar for Properties, maybe with built-in support for using Commons Configuration as the underlying provider (like what Spring Modules does)?
Colin Sampaleanu (blog author) says:
Added on December 1st, 2006 at 9:49 pm -QuoteThomas,
It doesn't make much sense to have tags that are that specialized. This would end up causing an explosion of tags. The whole point is these are supposed to be beans…
But your example is not very verbose even handled normally
@Bean
public MyJndiObject myJndiObject() {
return new JndiTemplate().lookup("java:comp/env/myJndiObject");
}
If the thing needs to be tweaked, then you can new the template and set properties separately.
Rod Johnson (blog author) says:
Added on December 2nd, 2006 at 4:53 am -QuoteJeppe
What you describe is very very similar in concept to the first Java configuration approach I tried back in 2004–"recording" calls with CGLIB. (This code is probably still in the sandbox somewhere, unless someone has killed it.) I'd be interesting in discussing your experience, as real world usage is key to getting this ready for prime time.
The recording approach certainly has many of the same advantages as the @Bean approach. However, I found that the reaction from folks (even the core Spring team) was a lot less positive to that style in general than the @Bean style…
Rgds
Rod
Rod Johnson (blog author) says:
Added on December 2nd, 2006 at 4:56 am -QuoteColin
I agree. The annotations should be conceptual, not implementation-specific. So the notion of an external property would certainly justify an annotation; JNDI is just one strategy for locating something, and that could lead to an explosion. Static factory methods might also be a good approach–more flexible than concrete inheritance from support classes that know about JNDI or something else environment-specific.
Rgds
Rod
Jeppe Cramon says:
Added on December 2nd, 2006 at 7:28 am -QuoteOn December 2, 2006 at 4:53 am, Rod Johnson said:
We've only been using it for about two months on two different projects, so I can only comment this far
For starters people had to get used to the "magic" that happens. I found that this was more because they wanted to know what happens underneath, than it was something against the approach. Generic and varargs make it really easy to do this while avoiding unnecessary casts (I dunno if your implementation used generics?).
The most annoying issue is with final classes, but we've handled that with wrappers (as in the example).
We've used the CgLib method recording for other scenarios, such as UI component to model binding, and apart from having to perform the CgLib wrapping method call, bean(…) or bind(..), it has worked quite well and people have enjoyed working with it as it solves more problems than it creates. It allows them work with the Java API without having to adhere to a specific api (other than the wrapping) or resort to strings/xml or other approaches to solving this problem.
/Jeppe
Alex says:
Added on December 2nd, 2006 at 10:01 am -QuoteYes, I had toyed around with a similar idea. My Spring-less alternative was a two fold approach.
Implement dependency injection as "your individual components get their dependencies injected externally" and "you have several classes/components which assemble smaller components and inject their dependencies".
These "assembler" classes can be helped with what I call a "lazy-proxy". Your assembler looks exactly like your MyConfig class, sans annotations. But instead of instantiating it directly, you instantiate it via a Proxy factory which creates classes that implement MyConfig delegating to the actual MyConfig class, but maintaining a lazy cache (i.e. the result of the first rod() call is cached, subsequent calls return the cached object).
The problem here is that you need interfaces, which can be annoying.
OTOH, this allows you to have "configuration interfaces". At work, we split our configuration in lots of beans xml files. We also have alternative configurations (i.e. a JDBC DAO, an Hibernate DAO, etc.) which can be used; these "implement" some beans (i.e. both JDBC DAO and Hibernate DAO provide a "booksDAO" bean)- it would be nice to have a notion of Bean Config interface which specifies a set of beans that a bean.xml file must declare.
Costin Leau says:
Added on December 2nd, 2006 at 2:04 pm -QuoteGuys, just wanted to inform you that I've moved the project structure to maven2 so now compiling and running the tests should be straight forward.
Deniz Oguz says:
Added on December 2nd, 2006 at 3:36 pm -QuoteThis is a very helpful feature. Our main context xml file is import of other xml files. We may go with a hybrid option and keep our main xml and replace other xml files with annotations. This may provide more static safety. Actually it is a matter of preference, and I always prefer annotation to xml.
Rodrigo Urubatan says:
Added on