1. Trang chủ >
  2. Công Nghệ Thông Tin >
  3. Kỹ thuật lập trình >

3-8. Auto-Wiring Beans with @Autowired and @Resource

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.49 MB, 753 trang )


9799ch03.qxd



5/5/08



4:50 PM



Page 65



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



How It Works

To ask Spring to auto-wire the bean properties with @Autowired or @Resource, you have to register an AutowiredAnnotationBeanPostProcessor instance in the IoC container. If you are using

a bean factory, you have to register this bean post processor through the API. Otherwise, you

can just declare an instance of it in your application context.



Or you can simply include the element in your bean configuration file and an AutowiredAnnotationBeanPostProcessor instance will automatically get

registered.


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.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd">



...





Auto-Wiring a Single Bean of Compatible Type

The @Autowired annotation can be applied to a particular property for Spring to auto-wire it.

As an example, you can annotate the setter method of the prefixGenerator property with

@Autowired. Then Spring will attempt to wire a bean whose type is compatible with

PrefixGenerator.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

...

@Autowired

public void setPrefixGenerator(PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

}

If you have a bean whose type is compatible with PrefixGenerator defined in the IoC container, it will be set to the prefixGenerator property automatically.



65



9799ch03.qxd



66



5/5/08



4:50 PM



Page 66



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING





...


class="com.apress.springrecipes.sequence.SequenceGenerator">








class="com.apress.springrecipes.sequence.DatePrefixGenerator">







By default, all the properties with @Autowired are required. When Spring can’t find a

matching bean to wire, it will throw an exception. If you would like a certain property to be

optional, set the required attribute of @Autowired to false. Then when Spring can’t find a

matching bean, it will leave this property unset.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

...

@Autowired(required = false)

public void setPrefixGenerator(PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

}

In addition to the setter method, the @Autowired annotation can also be applied to a constructor. Then Spring will attempt to find a bean with the compatible type for each of the

constructor arguments.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

...

@Autowired

public SequenceGenerator(PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

}

The @Autowired annotation can also be applied to a field, even if it is not declared as

public. In this way, you can omit the need of declaring a setter method or a constructor for



9799ch03.qxd



5/5/08



4:50 PM



Page 67



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



this field. Spring will inject the matched bean into this field via reflection. However, annotating a non-public field with @Autowired will reduce code testability since the code will be

difficult to unit test.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

@Autowired

private PrefixGenerator prefixGenerator;

...

}

You may even apply the @Autowired annotation to a method with an arbitrary name and

an arbitrary number of arguments. Then Spring will attempt to wire a bean with the compatible type for each of the method arguments.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

...

@Autowired

public void inject(PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

}



Auto-Wiring All Beans of Compatible Type

The @Autowired annotation can also be applied to a property of array type to have Spring autowire all the matching beans. For example, you can annotate a PrefixGenerator[] property

with @Autowired. Then Spring will auto-wire all the beans whose type is compatible with

PrefixGenerator at one time.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

@Autowired

private PrefixGenerator[] prefixGenerators;

...

}



67



9799ch03.qxd



68



5/5/08



4:50 PM



Page 68



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



If you have multiple beans whose type is compatible with the PrefixGenerator defined in

the IoC container, they will be added to the prefixGenerators array automatically.



...


class="com.apress.springrecipes.sequence.DatePrefixGenerator">






class="com.apress.springrecipes.sequence.DatePrefixGenerator">







In a similar way, you can apply the @Autowired annotation to a type-safe collection. Spring

is able to read the type information of this collection and auto-wire all the beans whose type is

compatible.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

@Autowired

private List prefixGenerators;

...

}

If Spring notices that the @Autowired annotation is applied to a type-safe java.util.Map

with strings as the keys, it will add all the beans of the compatible type, with the bean names

as the keys, to this map.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

@Autowired

private Map prefixGenerators;

...

}



9799ch03.qxd



5/5/08



4:50 PM



Page 69



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



Auto-Wiring by Type with Qualifiers

By default, auto-wiring by type will not work when there is more than one bean with the compatible type in the IoC container. However, Spring allows you to specify a candidate bean by

providing its name in the @Qualifier annotation.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

public class SequenceGenerator {

@Autowired

@Qualifier("datePrefixGenerator")

private PrefixGenerator prefixGenerator;

...

}

Then Spring will attempt to find a bean with that name in the IoC container and wire it

into the property.


class="com.apress.springrecipes.sequence.DatePrefixGenerator">





The @Qualifier annotation can also be applied to a method argument for auto-wiring.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

public class SequenceGenerator {

...

@Autowired

public void inject(

@Qualifier("datePrefixGenerator") PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

}

You can further create a custom qualifier annotation type for the auto-wiring purpose.

This annotation type must be annotated with @Qualifier itself.

package com.apress.springrecipes.sequence;

...

import org.springframework.beans.factory.annotation.Qualifier;



69



9799ch03.qxd



70



5/5/08



4:50 PM



Page 70



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.PARAMETER })

@Qualifier

public @interface Generator {

String value();

}

Then you can apply this annotation to an @Autowired bean property. It will ask Spring to

auto-wire the bean with this qualifier annotation and the specified value.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

@Autowired

@Generator("prefix")

private PrefixGenerator prefixGenerator;

...

}

You have to provide this qualifier to the target bean that you want to be auto-wired into

the preceding property. The qualifier is added by the element with the type attribute. The qualifier value is specified in the value attribute.


class="com.apress.springrecipes.sequence.DatePrefixGenerator">









Auto-Wiring by Name

If you would like to auto-wire bean properties by name, you can annotate a setter method, a

constructor, or a field with the JSR-250 @Resource annotation. By default, Spring will attempt

to find a bean with the same name as this property. But you can specify the bean name

explicitly in its name attribute.



■Note To use the JSR-250 annotations, you have to include common-annotations.jar (located in the

lib/j2ee directory of the Spring installation) in your classpath. However, if your application is running on



Java SE 6 or Java EE 5, you needn’t include this JAR file.



9799ch03.qxd



5/5/08



4:50 PM



Page 71



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



package com.apress.springrecipes.sequence;

import javax.annotation.Resource;

public class SequenceGenerator {

@Resource(name = "datePrefixGenerator")

private PrefixGenerator prefixGenerator;

...

}



3-9. Inheriting Bean Configuration

Problem

When configuring beans in the Spring IoC container, you may have more than one bean

sharing some common configurations, such as bean properties and attributes in the

element. You often have to repeat these configurations for multiple beans.



Solution

Spring allows you to extract the common bean configurations to form a parent bean. The

beans that inherit from this parent bean are called child beans. The child beans will inherit the

bean configurations, including bean properties and attributes in the element, from the

parent bean to avoid duplicate configurations. The child beans can also override the inherited

configurations when necessary.

The parent bean can act as a configuration template and also as a bean instance at the

same time. However, if you want the parent bean to act only as a template that cannot be

retrieved, you must set the abstract attribute to true, asking Spring not to instantiate this

bean.

You must note that not all attributes defined in the parent element will be inherited. For example, the autowire and dependency-check attributes will not be inherited from the

parent. To find out more about which attributes will be inherited from the parent and which

won’t, please refer to the Spring documentation about bean inheritance.



How It Works

Suppose you need to add a new sequence generator instance whose initial value and suffix are

the same as the existing ones.




class="com.apress.springrecipes.sequence.SequenceGenerator">











71



9799ch03.qxd



72



5/5/08



4:50 PM



Page 72



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING




class="com.apress.springrecipes.sequence.SequenceGenerator">










class="com.apress.springrecipes.sequence.DatePrefixGenerator">







To avoid duplicating the same properties, you can declare a base sequence generator

bean with those properties set. Then the two sequence generators can inherit this base generator so that they also have those properties set automatically. You needn’t specify the class

attributes of the child beans if they are the same as the parent’s.




class="com.apress.springrecipes.sequence.SequenceGenerator">













...



The inherited properties can be overridden by the child beans. For example, you can add

a child sequence generator with a different initial value.




class="com.apress.springrecipes.sequence.SequenceGenerator">















...





9799ch03.qxd



5/5/08



4:50 PM



Page 73



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



The base sequence generator bean can now be retrieved as a bean instance to use. If you

want it to act as a template only, you have to set the abstract attribute to true. Then Spring

will not instantiate this bean.


class="com.apress.springrecipes.sequence.SequenceGenerator">

...



You can also omit the class of the parent bean and let the child beans specify their own,

especially when the parent bean and child beans are not in the same class hierarchy, but

share some properties of the same name. In this case, the parent bean’s abstract attribute

must be set to true, as the parent bean can’t be instantiated. For example, let’s add another

ReverseGenerator class that has an initial property also.

package com.apress.springrecipes.sequence;

public class ReverseGenerator {

private int initial;

public void setInitial(int initial) {

this.initial = initial;

}

}

Now SequenceGenerator and ReverseGenerator don’t extend the same base class—that is,

they’re not in the same class hierarchy, but they have a property of the same name: initial. To

extract this common initial property, you need a baseGenerator parent bean with no class

attribute defined.










class="com.apress.springrecipes.sequence.SequenceGenerator">








class="com.apress.springrecipes.sequence.ReverseGenerator" />







73



9799ch03.qxd



74



5/5/08



4:50 PM



Page 74



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING





...



...



Figure 3-3 shows the object diagram for this generator bean hierarchy.



Figure 3-3. Object diagram for the generator bean hierarchy



3-10. Defining Collections for Bean Properties

Problem

Sometimes your bean properties may be of a collection type that contains multiple elements.

You would like to configure these collection properties in Spring’s bean configuration file

rather than by coding.



Solution

The Java Collections framework defines a set of interfaces, implementations, and algorithms

for different types of collections, such as lists, sets, and maps. Figure 3-4 shows a simplified

UML class diagram that may help you to understand the Java Collections framework better.

List, Set, and Map are the core interfaces representing three main types of collections. For

each collection type, Java provides several implementations with different functions and characteristics from which you can choose. In Spring, these types of collections can be easily

configured with a group of built-in XML tags, such as , , and .



9799ch03.qxd



5/5/08



4:50 PM



Page 75



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



Figure 3-4. Simplified class diagram for the Java Collections framework



How It Works

Suppose you are going to allow more than one suffix for your sequence generator. The suffixes

will be appended to the sequence numbers with hyphens as the separators. You may consider

accepting suffixes of arbitrary data types and converting them into strings when appending to

the sequence numbers.

Lists, Arrays, and Sets

First, let’s use a java.util.List collection to contain your suffixes. A list is an ordered and

indexed collection whose elements can be accessed either by index or with a for-each loop.

package com.apress.springrecipes.sequence;

...

public class SequenceGenerator {

...

private List suffixes;

public void setSuffixes(List suffixes) {

this.suffixes = suffixes;

}

public synchronized String getSequence() {

StringBuffer buffer = new StringBuffer();

...

for (Object suffix : suffixes) {

buffer.append("-");

buffer.append(suffix);

}

return buffer.toString();

}

}



75



Xem Thêm