Customizing Annotation Configuration and Component Detection in Spring 2.1 |
|

NOTE: This post has been updated as of May 31, 2007 to reflect the state of the 2.1-M2 official release
Two weeks ago I blogged about the new annotation-driven dependency injection capabilities of Spring 2.1, and I mentioned that I would follow-up with more info "later in the week". It turns out that was a bit optimistic, but the good news is the functionality has evolved quite a bit in the meantime. Therefore, to follow along with the examples here you will need to download the 2.1-M2 official release (or if you are one of the first people to read this updated entry and M2 is not yet available, you should grab at least nightly build #115 which you can download here).
The first thing I want to demonstrate is how to create an application context without using any XML. For those who have used Spring's BeanDefinitionReader implementations, this will look very familiar. Before creating the context however, we need a few "candidate" beans on the classpath. Continuing with the example from my previous blog, I have the following two interfaces:
public interface GreetingService {
String greet(String name);
}
public interface MessageRepository {
String getMessage(String language);
}
…and these corresponding implementations:
@Component
public class GreetingServiceImpl implements GreetingService {
@Autowired
private MessageRepository messageRepository;
public String greet(String name) {
Locale locale = Locale.getDefault();
if (messageRepository == null) {
return "Sorry, no messages";
}
String message = messageRepository.getMessage(locale.getDisplayLanguage());
return message + " " + name;
}
}
@Repository
public class StubMessageRepository implements MessageRepository {
Map<String,String> messages = new HashMap<String,String>();
@PostConstruct
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
public String getMessage(String language) {
return messages.get(language);
}
}
Now as promised… to assemble this admittedly trivial "application" without any XML:
Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog"); // the parameter is 'basePackage'
context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);
And the result:
Willkommen Standalone Beans
Essentially, this is the exact same behavior as when using the component-scan XML element from the new "context" namespace (as demonstrated in my previous blog). However, I want to focus on some of the newer features as well as customization options. First, I will remove the @Repository annotation from the StubMessageRepository, and rerun the tests which produces the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [blog.MessageRepository] is defined: expected single bean but found 0
Clearly the @Autowired annotation indicates a required dependency by default, but this can easily be switched by adding the 'required' parameter with a value of 'false', such as:
@Component
public class GreetingServiceImpl implements GreetingService {
@Autowired(required=false)
private MessageRepository messageRepository;
...
The result after this modification:
Sorry, no messages
To make things a bit more interesting, I will add the JDBC version of the MessageRepository (also from the previous post):
@Repository
public class JdbcMessageRepository implements MessageRepository {
private SimpleJdbcTemplate jdbcTemplate;
@Autowired
public void createTemplate(DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@PostConstruct
public void setUpDatabase() {
jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
}
@PreDestroy
public void tearDownDatabase() {
jdbcTemplate.update("drop table messages");
}
public String getMessage(String language) {
return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
}
}
As long as the stub version still does not contain the @Repository annotation, rerunning the tests will now produce the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcMessageRepository': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void blog.JdbcMessageRepository.createTemplate(javax.sql.DataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.sql.DataSource] is defined: expected single bean but found 0
Obviously a chain reaction of autowiring failures has resulted since no DataSource is available in the context. However, as a firm believer in test-driven development, I would like to unit test my implementation prior to setting up the infrastructure. Luckily, the scanner is fairly customizable, and I can provide filters, such as:
Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();
boolean useDefaultFilters = false;
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, useDefaultFilters);
scanner.addExcludeFilter(new AssignableTypeFilter(JdbcMessageRepository.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));
scanner.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile("blog\\.Stub.*")));
scanner.scan("blog");
context.refresh();
GreetingService greetingService =
(GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);
As you can see, I disabled the 'defaultFilters' and explicitly added my own. In this case, that was not completely necessary since the default includes the @Component and @Repository annotations, but I wanted to show the various filtering options – including not only annotations, but also assignable types and even regular expressions. The main goal of course was to disable the JDBC version of MessageRepository in favor of the stub, and according to my result, that is exactly what happened:
Willkommen Standalone Beans
Assuming that I am now ready to incorporate the JDBC version, I will likely need to include some XML configuration for the DataSource, such as:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.1.xsd">
<context:property-placeholder location="classpath:blog/jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
Then, I can combine the scanning with an XmlBeanDefinitionReader (notice that I have reverted to the default filters only):
Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog");
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/blog/dataSource.xml");
context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Hybrid Beans");
System.out.println(message);
The context contains both the scanned beans as well as those defined in XML, and the result is:
Willkommen Hybrid Beans
Up to this point, you've seen that 0 candidate beans will cause the autowiring to fail unless the 'required' parameter of @Autowired is set to false. Given that the autowiring is following 'by-type' semantics, more than 1 bean will cause a failure regardless of the required parameter's value. For example, after adding the @Repository annotation back to the StubMessageRepository and rerunning the previous example, I receive the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [blog.MessageRepository] is defined: expected single bean but found 2
This can be resolved by switching to 'by-name' semantics – accomplished via Spring 2.1's support for the JSR-250 @Resource annotation:
@Component
public class GreetingServiceImpl implements GreetingService {
@Resource(name="jdbcMessageRepository")
private MessageRepository messageRepository;
...
You probably noticed in the previous example that the bean name (as specified in the @Resource annotation) defaults to the decapitalized non-qualified classname. To override this behavior, it is possible to add your own implementation of the BeanNameGenerator strategy, such as:
private static class MyBeanNameGenerator implements BeanNameGenerator {
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
String fqn = definition.getBeanClassName();
return Introspector.decapitalize(fqn.replace("blog.", "").replace("Jdbc", ""));
}
}
Then providing this strategy to the scanner overrides the default:
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setBeanNameGenerator(new MyBeanNameGenerator());
scanner.scan("blog");
And therefore, the name specified in the @Resource annotation can be modified accordingly:
@Resource(name="messageRepository") private MessageRepository messageRepository;
NOTE: When relying on the container for autowiring, the default naming strategy is typically sufficient (i.e. it works "behind the scenes"). Therefore the naming strategy should only be considered for cases where you will be referring to beans by name elsewhere. Even then, for isolated cases it is much simpler to explicitly provide a bean name in the 'stereotype' annotation (e.g. @Repository("messageRepository")). Providing your own strategy can be useful if you are able to take advantage of naming conventions that are used consistently throughout your application (This particular example is a little contrived, but hopefully demonstrates that the strategy is very accommodating so that you can follow your own naming conventions).
So far all of the beans have been configured with the default 'singleton' scope, but scope resolution is another customizable strategy of the scanner. The default will look for a @Scope annotation on each component. For example, to configure the GreetingServiceImpl as a 'prototype', simply add the following:
@Scope("prototype")
@Component
public class GreetingServiceImpl implements GreetingService { .. }
While the default annotation approach is quite simple, scope is almost always a deployment-specific consideration. Therefore it often does not belong at the class-level or in the source code at all. For these reasons, the following strategy interface is available and may be specified on the scanner as with the BeanNameGenerator in the previous example:
public interface ScopeMetadataResolver {
ScopeMetadata resolveScopeMetadata(BeanDefinition definition);
}
Note that the name generation and scope resolution strategies may also be provided in the XML-based configuration, such as:
<context:component-scan base-package="blog"
name-generator="blog.MyBeanNameGenerator"
scope-resolver="blog.MyScopeMetadataResolver"/>
Likewise, custom filters can be added as sub-elements:
<context:component-scan base-package="blog" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:include-filter type="regex" expression="blog\.Stub.*"/>
<context:exclude-filter type="assignable" expression="blog.JdbcMessageRepository"/>
</context:component-scan>
I realize this entry has already covered quite a bit of ground, but there is one last topic I would like to cover. In the previous post, I included an aspect with the <aop:aspectj-autoproxy/> element. Now I want to demonstrate how to add the autoproxy behavior with our standalone version. First, the aspect itself (same as last time):
@Aspect
public class ServiceInvocationLogger {
private int invocationCount;
@Pointcut("execution(* blog.*Service+.*(..))")
public void serviceInvocation() {}
@Before("serviceInvocation()")
public void log() {
invocationCount++;
System.out.println("service invocation #" + invocationCount);
}
}
Next, I need to add an include filter for the @Aspect annotation (it is no longer included in the default filters):
scanner.addIncludeFilter(new AnnotationTypeFilter(Aspect.class));
scanner.scan("blog");
And finally, I need to register the AspectJ annotation-based autoproxy creator (prior to calling refresh() on the context):
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(context); context.refresh();
The result:
service invocation #1 Willkommen Hybrid Beans
Hopefully this entry and the preceding one have provided a sufficient introduction to these new features of Spring 2.1. You should now have a decent understanding of how to combine the component scanning and annotation configuration in small doses alongside "traditional" Spring XML configuration if you prefer. Also, by providing your own filters, name generators, and scope resolvers, you can customize the configuration process. The official 2.1-M2 release contains more detailed information in the reference documentation.
Stay tuned to this Interface21 Team Blog to learn about more new features as we continue to progress from the current milestone phase toward the RC1 release of Spring 2.1, and if you are not particularly excited about the annotation-driven configuration, then you may want to keep an eye out for an upcoming blog by Costin Leau on Spring Java Configuration – which offers yet another alternative to XML but without the invasiveness of annotations in your application code.
Similar Posts
- Annotation-Driven Dependency Injection in Spring 2.1
- More on Java Configuration
- Spring 2.0's JMS Improvements
- Using JPA in Spring without referencing Spring
- XPath Support in Spring Web Services









tony says:
Added on May 29th, 2007 at 10:45 amYour this article is very good
Jose Noheda says:
Added on May 30th, 2007 at 6:35 amHaving the @Resource annotation clarifies things IMO. The DI is simpler. I would need to toy a little with aspects, scopes and proxies but so far so good. Just one thing…why have you named it @Component when @Bean fits so nicely? It's driving me crazy
Bhavin Kamani says:
Added on June 10th, 2007 at 5:02 amI have 2 questions. Whats the difference between Repository and Component.
Also, I am having trouble using Repository annotation for my App. When I try using its throwing an exception. Here's the code, config file and the stack Trace. All I could figure out is that it happens during component scan.
public interface FormDataService {
public FormData save(FormData formData);
}
@Repository
public class FormDataDAO extends JpaDaoSupport implements FormDataService {
private static final Log logger = LogFactory.getLog(FormDataDAO.class);
public FormData save(FormData formData) {
if (formData.getId()==0) {
getJpaTemplate().persist(formData);
logger.info("Generated ID: " formData.getId());
} else {
getJpaTemplate().merge(formData);
}
return formData;
}
}
–>
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [spring-context.xml]; nested exception is java.lang.AbstractMethodError: org.springframework.core.type.asm.AnnotationMetadataReadingVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:375)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:280)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:142)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:158)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:184)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.springframework.test.jpa.AbstractJpaTests.runBare(AbstractJpaTests.java:209)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
Caused by: java.lang.AbstractMethodError: org.springframework.core.type.asm.AnnotationMetadataReadingVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
at org.objectweb.asm.ClassReader.accept(Unknown Source)
at org.objectweb.asm.ClassReader.accept(Unknown Source)
at org.springframework.core.type.filter.AnnotationTypeFilter.matchSelf(AnnotationTypeFilter.java:53)
at org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter.match(AbstractTypeHierarchyTraversingFilter.java:54)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isCandidateComponent(ClassPathScanningCandidateComponentProvider.java:183)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.getClassReaderIfCandidate(ClassPathScanningCandidateComponentProvider.java:166)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:148)
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:160)
at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:145)
at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:69)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1114)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1104)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:133)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:90)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:458)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:353)
… 24 more
Bhavin Kamani says:
Added on June 10th, 2007 at 5:09 amGuess my cofig xml file does not appear in my blog. Reposting it with CDATA tag hopefully it shd work.
–>
]]>
Bobby Quinne says:
Added on June 13th, 2007 at 1:11 amI am currently trying to code a dao :
@Repository(value="dao.my")
public class MyDao extends HibernateDaoSupport implements IMyDao
{
}
however at runtime I receive the following exception. Any ideas? Have I left something out? :
Unable to return specified BeanFactory instance: factory key [com.my], from group with resource name [classpath*:beanRefFactory.xml]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.my' defined in URL [file:/home/lore/development/projects/mainline/source/server/gen/spring/beanRefFactory.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao.configuration': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [com.tradecraft.demerol], from group with resource name [classpath*:beanRefFactory.xml]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.my' defined in URL [file:/home/lore/development/projects/mainline/source/server/gen/spring/beanRefFactory.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao.my': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:405)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.my' defined in URL [file:/home/lore/development/projects/mainline/source/server/gen/spring/beanRefFactory.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao.my': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:430)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:255)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:252)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:395)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao.configuration': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:98)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:178)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:781)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:699)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:386)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dao.configuration': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1178)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:407)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:255)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:252)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:689)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:358)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:91)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:75)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:83)
Caused by: java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required
at org.springframework.orm.hibernate3.support.HibernateDaoSupport.checkDaoConfig(HibernateDaoSupport.java:115)
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1205)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1175)
Caleb says:
Added on July 16th, 2007 at 9:52 amThanks for the walkthrough — this post and its predecessor have been very helpful in understanding the new annotation-based configuration options, the growth of which I have been excited to see!
I have a quick comment and a question. First, the question: Will there be a way of configuring factory beans using annotations, or is there a way of doing so already that I am simply too dense to realize? As I understand it, currently the only way to specify a factory method is through the XML configuration.
Now, the comment: I was surprised to read about your thought process in determining whether or not to include a way of configuring a bean's scope via an annotation. Certainly, the argument that a bean's scope should be a deployment-level configuration item is valid. However, most of us using Spring in our day-to-day development are constantly striking a balance between doing the "right" thing and doing the rapid thing. While a scope annotation breaches the separation of deployment description from bean description, in many cases a bean will only ever live in one scope, and there is a considerable benefit in convenience gained from having all of a bean's configuration specified right there in the source. Additionally, the Spring developers, it seems to me, have always championed choice and flexibility over proscription and rigidity, so I was very glad to see the introduction of the @Scope annotation.
Thanks for providing such a valuable framework. Spring rocks, and your continued dedication to flexibility will make Spring 2.1 rock even harder!
tom says:
Added on June 26th, 2008 at 9:30 pm[…] former peeps over at Yahoo just released 10 more components, 3 Flash and 5 Flex components. The also fixed some of the bugs […]
Mital Pritmani says:
Added on October 12th, 2011 at 1:46 amThanks for this post.
It solved my issue of "no unique bean of type is defined expected single matching bean but found 2" exception.
Greg says:
Added on November 3rd, 2011 at 5:47 amThis helped me to save a lot of time. Thanks !