This chapter covers
1.5 Autowiring and component scanning using annotations
1.5.3 Component scanning
}
Now you could completely wipe out the XML bean declaration, and the @Autowired accountDao field in AccountService would be automatically populated with a Jdbc-AccountDao instance. Although this is all well and good, there is another, more suit-able annotation that provides additional benefits specifically for DAOs.
The @Repository annotation is a specialization of the @Component annotation. It not only imports the DAOs into the DI container, but it also makes the unchecked exceptions that they throw eligible for translation into Spring DataAccessExceptions (also unchecked).
The @Service annotation is also a specialization of the component annotation. It doesn’t currently provide any additional behavior over the @Component annotation, but it’s a good idea to use @Service over @Component in service-layer classes because it specifies intent better. Additionally, tool support and additional behavior might rely on it in the future.
Finally, the @Controller annotation marks a class as a Spring Web MVC controller.
It too is a @Component specialization, so beans marked with it are automatically imported into the DI container. We haven’t talked much about Spring Web MVC yet, but we’ll be using it heavily throughout this book. Basically, when you add the @Controller anno-tation to a class, you can use another annoanno-tation, @RequestMapping, to map URLs to instance methods of a class. That is, you can tell Spring that you want a certain method invoked when a user agent requests one of your application’s URLs. We’ll get more into that later.
1.5.3 Component scanning
Just as you need to declare context:annotation-config to turn on autowiring, you need to declare context:component-scan to enable the importing of classes that are annotated with the stereotypes. The following listing shows how this is done.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source project: sip01, branch: 08 (Maven Project) -->
<beans xmlns="http://www.springframework.org/schema/beans"
Listing 1.11 Spring configuration modified to support component scanning
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/
➥ spring-context-3.1.xsd">
<context:component-scan base-package="com.springinpractice.ch01"/>
…
</beans>
The context:component-scan element requires a base-package attribute, which, as its name suggests, specifies a starting point for a recursive component search. Here you set it to com.springinpractice.ch01. Also, the component-scan element can be declared multiple times and pointed to multiple packages. It’s common to lay out package structures by application layer (which is the convention we follow for the rec-ipes in this book), so you might have packages for DAOs, services, and controllers. In that case, you’d declare three component-scan elements, each with a base-package attribute pointing to a different package.
Also, when component-scan is declared, you no longer need to declare con-text:annotation-config, because autowiring is implicitly enabled when component scanning is enabled.
Finally, you no longer need to declare the flagged beans in your configuration. When component scanning kicks in at application startup, Spring will recurse over all the pack-ages you’ve specified, look for stereotype-annotated classes, and import them into the container. Their default bean names are their uncapitalized, nonqualified classnames.4 For example, springinpractice.ch01.dao.jdbc.JdbcAccountDao resolves to jdbc-AccountDao. The resulting configuration file looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Source project: sip01, branch: 08 (Maven Project) -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
4 If the default bean names aren’t suitable for your purposes, you can implement Spring’s BeanNameGenerator interface to customize the naming strategy. Then, when declaring the component-scan element, tack on the name-generator attribute and point it to the name of your custom BeanNameGenerator. See Rod Johnson et al, “Naming autodetected components,” The Spring Framework Reference Documentation, SpringSource, http://mng.bz/23kk.
Listing 1.12 Final Spring configuration using component scanning
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/
➥ spring-context-3.1.xsd">
<context:component-scan base-package="com.springinpractice.ch01"/>
<bean
class="org.springframework.beans.factory.config.
➥ PropertyPlaceholderConfigurer"
p:location="springbook.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${dataSource.driverClassName}"
p:url="${dataSource.url}"
p:username="${dataSource.username}"
p:password="${dataSource.password}"/>
</beans>
Because you enable component scanning and use the @Service annotation in the accountService and @Repository annotation in the accountDao, you no longer need to specify their configuration in XML. Because you’re using a compiled class from a third-party library (BasicDataSource), you’re unable to decorate its code with anno-tations. As a result, you must still specify its configuration here.
1.5.4 XML vs. annotations: which is better?
Throughout the book, we’ll use annotation-based configuration liberally. Many of the recipes use Hibernate, JPA, and Hibernate Validator annotations as well. This in part reflects the general direction in which the Spring team is steering, and in part reflects the fact that annotations are more convenient and usable in a wide variety of situations.
The choice of whether to use XML or annotations for configuration is the subject of much community debate. With XML the configuration is centralized into a set of files, and each file is typically dedicated to a particular architectural concern or slice.
For example, if you had a Spring configuration file for DAOs and another for services and you wanted to change something, you’d pull up the appropriate file, scan through it, and make the change. It’s easy to locate the file, but depending how large it is, it could be difficult to scan through. Additionally, keeping configuration in the XML keeps POJOs clean, which is a big part of the argument for using Spring in the first place. Distributing configuration makes it more challenging to replace one piece of infrastructure technology with another.
On the other hand, if you use annotations, your configuration is consolidated according to application verticals. We prefer this because feature changes are likely to span architectural slices, and it’s nice to be able to change things in one place. For instance, if you needed to add a field to a domain class, you’d open the class in your IDE, add the field, and add JPA and Bean Validation Framework annotations to it at the same time. This is easier than opening each respective XML configuration file, scanning through it, and making the necessary changes. Another benefit of using
annotations is that it’s easy to get a 360-degree view of individual domain services and objects.
Some XML configuration will still be necessary. You need to enable component scanning in XML, and Spring ships with several classes that can only be configured with XML.
1.6 Summary
This chapter has provided a brief overview of the Spring Framework, its major pieces, and its underlying principles, including inversion of control and how it relates to dependency injection. Through several examples, we’ve demonstrated the benefits of using Spring to manage an application’s dependencies and described how to define these dependencies using both XML and Java annotations.
In the next chapter, we’ll move away from the container and explore some of the (very) useful components that Spring provides around persistence, object-relational mapping, and transaction management. In many cases, you can incorporate these components into your application in a transparent fashion.
33