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

3-7. Auto-Wiring Beans with XML Configuration

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 61



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



Mode



Description



autodetect



If a default constructor with no argument is found, the dependencies will be

auto-wired by type. Otherwise, they will be auto-wired by constructor.



* The default mode is no, but this can be changed by setting the default-autowire attribute of the

root element. This default mode will be overridden by a bean’s own mode if specified.



Although the auto-wiring feature is very powerful, the cost is that it will reduce the readability of your bean configurations. As auto-wiring is performed by Spring at runtime, you

cannot derive how your beans are wired from the bean configuration file. In practice, I recommend applying auto-wiring only in applications whose component dependencies are not

complicated.



How It Works

Auto-Wiring by Type

You can set the autowire attribute of the sequenceGenerator bean to byType and leave the

prefixGenerator property unset. Then Spring will attempt to wire a bean whose type is compatible with PrefixGenerator. In this case, the datePrefixGenerator bean will be wired

automatically.




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

autowire="byType">








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







The main problem of auto-wiring by type is that sometimes there will be more than one

bean in the IoC container compatible with the target type. In this case, Spring will not be able

to decide which bean is most suitable for the property, and hence cannot perform autowiring. For example, if you have another prefix generator generating the current year as the

prefix, auto-wiring by type will be broken immediately.




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

autowire="byType">









61



9799ch03.qxd



62



5/5/08



4:50 PM



Page 62



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING




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






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







Spring will throw an UnsatisfiedDependencyException if more than one bean is found for

auto-wiring.

Exception in thread "main"

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating

bean with name 'sequenceGenerator' defined in class path resource [beans.xml]:

Unsatisfied dependency expressed through bean property 'prefixGenerator': No unique

bean of type [com.apress.springrecipes.sequence.PrefixGenerator] is defined:

expected single matching bean but found 2: [datePrefixGenerator,

yearPrefixGenerator]



Auto-Wiring by Name

Another mode of auto-wiring is byName, which can sometimes resolve the problems of autowiring by type. It works very similarly to byType, but in this case, Spring will attempt to wire a

bean with the same name, rather than with the compatible type. As the bean name is unique

within a container, auto-wiring by name will not cause ambiguity.




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

autowire="byName">








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







However, auto-wiring by name will not work in all cases. Sometimes it’s not possible for

you to make the name of the target bean the same as your property. In practice, you often

need to specify ambiguous dependencies explicitly, while keeping others auto-wired. That

means you employ a mixture of explicit wiring and auto-wiring.



9799ch03.qxd



5/5/08



4:50 PM



Page 63



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING



Auto-Wiring by Constructor

The auto-wiring mode constructor works like byType, but it’s rather more complicated. For a

bean with a single constructor, Spring will attempt to wire a bean with a compatible type for

each constructor argument. But for a bean with multiple constructors, the process is more

complicated. Spring will first attempt to find a bean with a compatible type for each argument

of each constructor. Then it will pick the constructor with the most matching arguments.

Suppose that SequenceGenerator has one default constructor and one constructor with an

argument PrefixGenerator.

package com.apress.springrecipes.sequence;

public class SequenceGenerator {

public SequenceGenerator() {}

public SequenceGenerator(PrefixGenerator prefixGenerator) {

this.prefixGenerator = prefixGenerator;

}

...

}

In this case, the second constructor will be matched and picked because Spring can find a

bean whose type is compatible with PrefixGenerator.




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

autowire="constructor">








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







However, multiple constructors in a class may cause ambiguity in constructor argument

matching. The situation may be further complicated if you ask Spring to determine a constructor for you. So, if you use this auto-wiring mode, take great care to avoid ambiguity.

Auto-Wiring by Auto-Detection

The auto-wiring mode autodetect asks Spring to decide the auto-wiring mode between

byType and constructor. If a default constructor with no argument is found for that bean,

byType will be chosen. Otherwise, constructor will be chosen. As the SequenceGenerator class

has a default constructor defined, byType will be chosen. That means the prefix generator will

be injected via the setter method.



63



9799ch03.qxd



64



5/5/08



4:50 PM



Page 64



CHAPTER 3 ■ BEAN CONFIGURATION IN SPRING






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

autowire="autodetect">








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









Auto-Wiring and Dependency Checking

As you have seen, if Spring finds more than one candidate bean for auto-wiring, it will throw

an UnsatisfiedDependencyException. On the other hand, if the auto-wiring mode is set to

byName or byType, and Spring cannot find a matching bean to wire, it will leave the property

unset, which may cause a NullPointerException or a value that has not been initialized.

However, if you would like to be notified when auto-wiring cannot wire your beans, you

should set the dependency-check attribute to objects or all. In that case, an

UnsatisfiedDependencyException will be thrown whenever auto-wiring doesn’t work.


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

autowire="byName" dependency-check="objects">









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

Problem

Auto-wiring by setting the autowire attribute in the bean configuration file will wire all properties of a bean. It’s not flexible enough to wire particular properties only. Moreover, you can

only auto-wire beans either by type or by name. If neither strategy satisfies your requirements,

you must wire your beans explicitly.



Solution

Spring 2.5 makes extensive enhancements to the auto-wiring feature. You can auto-wire a particular property by annotating a setter method, a constructor, a field, or even an arbitrary

method with the @Autowired annotation, or the @Resource annotation defined in JSR-250:

Common Annotations for the Java Platform. That means you have one more option besides

setting the autowire attribute to satisfy your requirements. However, this annotation-based

option requires you to be using Java 1.5 or higher.



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



Xem Thêm
Tải bản đầy đủ (.pdf) (753 trang)

×