Most examples in this chapter use XML to specify the configuration
metadata that produces each BeanDefinition
within the Spring container. The previous section (Section 3.9, “Annotation-based container configuration”) demonstrates how to provide a lot of
the configuration metadata through source-level annotations. Even in those
examples, however, the "base" bean definitions are explicitly defined in
the XML file, while the annotations only drive the dependency injection.
This section describes an option for implicitly detecting the
candidate components by scanning the classpath.
Candidate components are classes that match against a filter criteria and
have a corresponding bean definition registered with the container. This
removes the need to use XML to perform bean registration, instead you can
use annotations (for example @Component), AspectJ type expressions, or
your own custom filter criteria to select which classes will have bean
definitions registered with the container.
Note | |
---|---|
Starting with Spring 3.0, many features provided by the Spring JavaConfig
project are part of the core Spring Framework. This allows you
to define beans using Java rather than using the traditional XML files.
Take a look at the |
In Spring 2.0 and later, the
@Repository
annotation is a marker for
any class that fulfills the role or stereotype
(also known as Data Access Object or DAO) of a repository. Among the
uses of this marker is the automatic translation of exceptions as
described in Section 13.2.2, “Exception translation”.
Spring 2.5 introduces further stereotype annotations:
@Component
,
@Service
, and
@Controller
.
@Component
is a generic stereotype for
any Spring-managed component.
@Repository
,
@Service
, and
@Controller
are specializations of
@Component
for more specific use cases,
for example, in the persistence, service, and presentation layers,
respectively. Therefore, you can annotate your component classes with
@Component
, but by annotating them with
@Repository
,
@Service
, or
@Controller
instead, your classes are
more properly suited for processing by tools or associating with
aspects. For example, these stereotype annotations make ideal targets
for pointcuts. It is also possible that
@Repository
,
@Service
, and
@Controller
may carry additional
semantics in future releases of the Spring Framework. Thus, if you are
choosing between using @Component
or
@Service
for your service layer,
@Service
is clearly the better choice.
Similarly, as stated above, @Repository
is already supported as a marker for automatic exception translation in
your persistence layer.
Spring can automatically detect stereotyped classes and register
corresponding BeanDefinition
s with the
ApplicationContext
. For example, the
following two classes are eligible for such autodetection:
@Service public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
@Repository public class JpaMovieFinder implements MovieFinder { // implementation elided for clarity }
To autodetect these classes and register the corresponding beans, you need to include the following element in XML, where the base-package element is a common parent package for the two classes. (Alternatively, you can specify a comma-separated list that includes the parent package of each class.)
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="org.example"/> </beans>
Note | |
---|---|
The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do not activate the files-only switch of the JAR task. |
Furthermore, the
AutowiredAnnotationBeanPostProcessor
and
CommonAnnotationBeanPostProcessor
are
both included implicitly when you use the component-scan element. That
means that the two components are autodetected and
wired together - all without any bean configuration metadata provided in
XML.
Note | |
---|---|
You can disable the registration of
|
Note | |
---|---|
In Spring 3.0 RC1 you can use JSR 330's
|
By default, classes annotated with
@Component
,
@Repository
,
@Service
,
@Controller
, or a custom annotation that
itself is annotated with @Component
are
the only detected candidate components. However, you can modify and
extend this behavior simply by applying custom filters. Add them as
include-filter or
exclude-filter sub-elements of the
component-scan
element. Each filter element requires
the type
and expression
attributes. The following table describes the filtering options.
Table 3.5. Filter Types
Filter Type | Example Expression | Description |
---|---|---|
annotation | org.example.SomeAnnotation | An annotation to be present at the type level in target components. |
assignable | org.example.SomeClass | A class (or interface) that the target components are assignable to (extend/implement). |
aspectj | org.example..*Service+ | An AspectJ type expression to be matched by the target components. |
regex | org\.example\.Default.* | A regex expression to be matched by the target components class names. |
custom | org.example.MyTypeFilter | A custom implementation of the
org.springframework.core.type
.TypeFilter interface. |
The following example shows the XML configuration ignoring all
@Repository
annotations and using "stub"
repositories instead.
<beans> <context:component-scan base-package="org.example"> <context:include-filter type="regex" expression=".*Stub.*Repository"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan> </beans>
Note | |
---|---|
You can also disable the default filters by providing
use-default-filters="false" as an attribute of
the <component-scan/> element. This will in effect disable
automatic detection of classes annotated with
|
Spring components can also contribute bean definition metadata to
the container. You do this with the same @Bean
annotation used to define bean metadata within
@Configuration
annotated classes. Here is a simple
example:
@Component public class FactoryMethodComponent { @Bean @Qualifier("public") public TestBean publicInstance() { return new TestBean("publicInstance"); } public void doWork() { // Component method implementation omitted } }
This class is a Spring component that has application-specific
code contained in its doWork
method. However,
it also contributes a bean definition that has a factory method
referring to the method publicInstance
. The
@Bean
annotation identifies the factory method and
other bean definition properties, such as a qualifier value through the
@Qualifier
annotation. Other method level
annotations that can be specified are @Scope
,
@Lazy
, and custom qualifier annotations. Autowired
fields and methods are supported as previously discussed, with
additional support for autowiring of @Bean
methods:
@Component public class FactoryMethodComponent { private static int i; @Bean @Qualifier("public") public TestBean publicInstance() { return new TestBean("publicInstance"); } // use of a custom qualifier and autowiring of method parameters @Bean @BeanAge(1) protected TestBean protectedInstance(@Qualifier("public") TestBean spouse, @Value("#{privateInstance.age}") String country) { TestBean tb = new TestBean("protectedInstance", 1); tb.setSpouse(tb); tb.setCountry(country); return tb; } @Bean @Scope(BeanDefinition.SCOPE_SINGLETON) private TestBean privateInstance() { return new TestBean("privateInstance", i++); } @Bean @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public TestBean requestScopedInstance() { return new TestBean("requestScopedInstance", 3); } }
The example autowires the String
method
parameter country
to the value of the
Age
property on another bean named
privateInstance
. A Spring Expression Language element
defines the value of the property through the notation #{
<expression> }
. For @Value
annotations, an expression resolver is preconfigured to look for bean
names when resolving expression text.
The @Bean
methods in a Spring component are
processed differently than their counterparts inside a Spring
@Configuration
class. The difference is that
@Component
classes are not enhanced with CGLIB to
intercept the invocation of methods and fields. CGLIB proxying is the
means by which invoking methods or fields within
@Configuration
classes @Bean
methods create bean metadata references to collaborating objects.
Methods are not invoked with normal Java semantics.
In contrast, calling a method or field within a
@Component
classes @Bean
method
has standard Java semantics.
When a component is autodetected as part of the scanning process,
its bean name is generated by the
BeanNameGenerator
strategy known to that
scanner. By default, any Spring stereotype annotation
(@Component
,
@Repository
,
@Service
, and
@Controller
) that contains a
name
value will thereby provide that name to the
corresponding bean definition.
Note | |
---|---|
JSR 330's @Named annotation can be used as a mean to both detect components and to provide them with a name. This behavior is enabled automatically if you have the JSR 330 jar on the classpath. |
If such an annotation contains no name
value or
for any other detected component (such as those discovered by custom
filters), the default bean name generator returns the uncapitalized
non-qualified class name. For example, if the following two components
were detected, the names would be myMovieLister and
movieFinderImpl:
@Service("myMovieLister") public class SimpleMovieLister { // ... }
@Repository public class MovieFinderImpl implements MovieFinder { // ... }
Note | |
---|---|
If you do not want to rely on the default bean-naming strategy,
you can provide a custom bean-naming strategy. First, implement the
|
<beans> <context:component-scan base-package="org.example" name-generator="org.example.MyNameGenerator" /> </beans>
As a general rule, consider specifying the name with the annotation whenever other components may be making explicit references to it. On the other hand, the auto-generated names are adequate whenever the container is responsible for wiring.
As with Spring-managed components in general, the default and most
common scope for autodetected components is singleton. However,
sometimes you need other scopes, which Spring 2.5 provides with a new
@Scope
annotation. Simply provide the
name of the scope within the annotation:
@Scope(StandardScopes.PROTOTYPE) @Repository public class MovieFinderImpl implements MovieFinder { // ... }
Note | |
---|---|
To provide a custom strategy for scope resolution rather than
relying on the annotation-based approach, implement the |
<beans> <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver" /> </beans>
When using certain non-singleton scopes, it may be necessary to generate proxies for the scoped objects. The reasoning is described in Section 3.5.4.5, “Scoped beans as dependencies”. For this purpose, a scoped-proxy attribute is available on the component-scan element. The three possible values are: no, interfaces, and targetClass. For example, the following configuration will result in standard JDK dynamic proxies:
<beans> <context:component-scan base-package="org.example" scoped-proxy="interfaces" /> </beans>
The @Qualifier
annotation is
discussed in Section 3.9.3, “Fine-tuning annotation-based autowiring with qualifiers”.
The examples in that section demonstrate the use of the
@Qualifier
annotation and custom
qualifier annotations to provide fine-grained control when you resolve
autowire candidates. Because those examples were based on XML bean
definitions, the qualifier metadata was provided on the candidate bean
definitions using the qualifier
or
meta
sub-elements of the bean
element in the XML. When relying upon classpath scanning for
autodetection of components, you provide the qualifier metadata with
type-level annotations on the candidate class. The following three
examples demonstrate this technique:
@Component @Qualifier("Action") public class ActionMovieCatalog implements MovieCatalog { // ... }
@Component @Genre("Action") public class ActionMovieCatalog implements MovieCatalog { // ... }
@Component @Offline public class CachingMovieCatalog implements MovieCatalog { // ... }
Note | |
---|---|
As with most annotation-based alternatives, keep in mind that the annotation metadata is bound to the class definition itself, while the use of XML allows for multiple beans of the same type to provide variations in their qualifier metadata, because that metadata is provided per-instance rather than per-class. |