spring in action Third 5

本文介绍了Spring框架如何通过自动装配和注解等方式减少XML配置文件的复杂度,提高开发效率。详细探讨了不同类型的自动装配及其限制,并展示了如何利用注解进行依赖注入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看到第三章了,越来越有趣了,第三章讲述spring是如何简化xml文件冗余繁琐的配置,从而更加简洁和方便的使用spring,和大家一起学习。

Minimizing XML configuration in Spring

Fortunately, Spring offers a few tricks to help cut down on the amount of XML configuration required:

¡ Autowiring helps reduce or even eliminate the need for <property> and <constructor-arg> elements by letting Spring automatically figure out how to wire bean dependencies. ¡ Autodiscovery takes autowiring a step further by letting Spring figure out which classes should be configured as Spring beans, reducing the need for the <bean> element.

3.1 Automatically wiring bean properties

Taking advantage of such obvious wirings, Spring offers autowiring. Rather than explicitly wiring bean properties, why not let Spring sort out those cases when there’s no question about which bean reference should be wired?

3.1.1 The four kinds of autowiring

When it comes to automatically wiring beans with their dependencies, Spring has a lot of clues to work from. As a result, Spring provides four flavors of autowiring:

¡ byName--Attempts to match all properties of the autowired bean with beans that have the same name (or ID) as the properties. Properties for which there’s no matching bean will remain unwired.

¡ byType--Attempts to match all properties of the autowired bean with beans whose types are assignable to the properties. Properties for which there’s no matching bean will remain unwired. ¡ constructor--Tries to match up a constructor of the autowired bean with beans whose types are assignable to the constructor arguments.

¡ autodetect--Attempts to apply constructor autowiring first. If that fails, byType will be tried.

AUTOWIRING BY NAME

<bean id="kenny2" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="Jingle Bells" /> <property name="instrument" ref="saxophone" /> </bean>

<bean id="instrument" class="com.springinaction.springidol.Saxophone" />

<bean id="kenny" class="com.springinaction.springidol.Instrumentalist" autowire="byName"> <property name="song" value="Jingle Bells" /> </bean>

AUTOWIRING BY TYPE

Autowiring using byType works in a similar way to byName, except that instead of con- sidering a property’s name, the property’s type is examined. When attempting to autowire a property by type, Spring will look for beans whose type is assignable to the property’s type.

But there’s a limitation to autowiring by type. What happens if Spring finds more than one bean whose type is assignable to the autowired property? In such a case, Spring isn’t going to guess which bean to autowire and will instead throw an exception.

To overcome ambiguities with autowiring by type, Spring offers two options: you can either identify a primary candidate for autowiring or you can eliminate beans from autowiring candidacy.

But here’s the weird side of the primary attribute: it defaults to true. That means that all autowire candidates will be primary (and thus none will be preferred). So, to use primary, you’ll need to set it to false for all of the beans that are not the primary choice. For example, to establish that the saxophone bean isn’t the primary choice when autowiring Instruments:

 <bean id="saxophone" class="com.springinaction.springidol.Saxophone" primary="false"/>

 

<bean id="saxophone" class="com.springinaction.springidol.Saxophone" autowire-candidate="false" />

AUTOWIRING CONSTRUCTORS

<bean id="duke" class="com.springinaction.springidol.PoeticJuggler" autowire="constructor" />

Autowiring by constructor shares the same limitations as byType.

BEST-FIT AUTOWIRING

<bean id="duke" class="com.springinaction.springidol.PoeticJuggler" autowire="autodetect"/>

When a bean has been configured to autowire by autodetect, Spring will attempt to autowire by constructor first. If a suitable constructor-to-bean match cant be found, then Spring will attempt to autowire by type.

3.1.2 Default autowiring

<?xml version="1.0" encoding="UTF-8"?>

 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

 default-autowire="byType">

 </beans>

Note that I said that default-autowire would be applied to all beans in a given Spring configuration file; I didn’t say that it would be applied to all beans in a Spring application context. You could have multiple configuration files that define a single application context, each with their own default autowiring setting.

Also, just because you’ve defined a default autowiring scheme, that doesn’t mean that you’re stuck with it for all of your beans. You can still override the default on a bean-by-bean basis using the autowire attribute.

3.1.3 Mixing auto with explicit wiring

Just because you choose to autowire a bean, that doesn’t mean you can’t explicitly wire some properties. You can still use the <property> element on any property just as if you hadn’t set autowire.

<bean id="kenny" class="com.springinaction.springidol.Instrumentalist" autowire="byType"> <property name="song" value="Jingle Bells" /> <property name="instrument" ref="saxophone" /> </bean>

As illustrated here, mixing automatic and explicit wiring is also a great way to deal with ambiguous autowiring that might occur when autowiring using byType.

<bean id="kenny" class="com.springinaction.springidol.Instrumentalist" autowire="byType"> <property name="song" value="Jingle Bells" /> <property name="instrument"><null/></property> </bean>

One final note on mixed wiring: when using constructor autowiring, you must let Spring wire all of the constructor arguments—you can’t mix <constructor-arg> ele-ments with constructor autowiring.

3.2 Wiring with annotations

The simplest way to do that is with the <context:annotation-config> element from Spring’s context configuration namespace:

<?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:annotation-config />

<!-- bean declarations go here -->

 </beans>

Spring 3 supports a few different annotations for autowiring:

¡ Spring’s own @Autowired annotation

¡ The @Inject annotation from JSR-330

¡ The @Resource annotation from JSR-250

3.2.1 Using @Autowired

@Autowired

public void setInstrument(Instrument instrument) {

this.instrument = instrument; }

When Spring sees that you’ve annotated setInstrument() with @Autowired it’ll try to perform byType autowiring on the method.

What’s especially interesting about @Autowired is that you don’t have to use it with a setter method. You can use it on any method to automatically wire in bean references:

@Autowired

 public voidheresYourInstrument(Instrumentinstrument){

this.instrument=instrument; }

The @Autowired annotation can even be used on constructors:

 @Autowired

public Instrumentalist(Instrumentinstrument){

this.instrument=instrument; }

 

@Autowired

private Instrument instrument;

 

If there are no applicable beans or if multiple beans could be autowired, then @Autowired will run into some trouble. Fortunately, there’s a way that we can help @Autowired out in those circumstances.

OPTIONAL AUTOWIRING

But it’s also possible that the property being wired is truly optional and a null value is acceptable. In that case, you can configure optional autowiring by setting @Autowired’s required attribute to false. For example:

 @Autowired(required=false)

 private Instrumentinstrument;

Here, Spring will try to wire the instrument property. But if no bean of type Instrument can be found, then no problem. The property will be left null.

Note that the required attribute can be used anywhere @Autowired can be used. But when used with constructors, only one constructor can be annotated with @Autowired and required set to true. All other @Autowired-annotated constructors must have required set to false. Moreover, when multiple constructors are anno- tated with @Autowired, Spring will choose the constructor which has the most argu- ments that can be satisfied.

QUALIFYING AMBIGUOUS DEPENDENCIES

To help @Autowired figure out which bean you want, you can accompany it with Spring’s @Qualifier annotation.

@Qualifier to specify a bean named guitar:

@Autowired @

Qualifier("guitar")

 private Instrumentinstrument;

 As shown here, the @Qualifier annotation will try to wire in a bean whose ID matches guitar.

In addition to narrowing by a bean’s ID, it’s also possible to narrow by a qualifier that’s applied to a bean itself. For example, suppose that the guitar bean were declared in XML as follows:

<bean class="com.springinaction.springidol.Guitar"> <qualifier value="stringed" /> </bean>

Here the <qualifier> element qualifies the guitar bean as a stringed instrument. But instead of specifying the qualifier in XML, you could have also annotated the Guitar class itself with the @Qualifier annotation:

@Qualifier("stringed") public classGuitarimplementsInstrument{ ... }

 

CREATING CUSTOM QUALIFIERS

@StringedInstrument

 public class Guitar implements Instrument { ... }

 

@Autowired

@StringedInstrument

private Instrument instrument;

 

When Spring tries to autowire the instrument property, it’ll narrow the selection of all Instrument beans down to just those that are annotated with @StringedInstrument. As long as only one bean is annotated with @StringedInstrument, it’ll be wired into the instrument property.

Spring’s @Autowired annotation is one way to cut down on the amount of Spring configuration XML. But it does create a Spring-specific dependency within the classes that use it (even if that dependency is just an annotation). Fortunately, Spring also supports a standard Java alternative to @Autowired. Let’s look at how to use @Inject from the Dependency Injection for Java specification.

3.2.2 Applying standards-based autowiring with @Inject

The centerpiece of JSR-330 is the @Inject annotation. This annotation is an almost complete drop-in replacement for Spring’s @Autowired annotation.

@Inject

private Instrumentinstrument;

Just like @Autowired, @Inject can be used to autowire properties, methods, and con- structors. Unlike @Autowired, @Inject doesnt have a required attribute. Therefore, @Inject-annotated dependencies are expected to be fulfilled, failing with an excep- tion if theyre not.

JSR-330 has another trick up its sleeve in addition to the @Inject annotation. Rather than inject a reference directly, you could ask @Inject to inject a Provider. The Provider interface enables, among other things, lazy injection of bean refer- ences and injection of multiple instances of a bean.

private Set<Knife> knives;

 @Inject

 public KnifeJuggler(Provider<Knife> knifeProvider) {

knives = new HashSet<Knife>(); for (int i = 0; i < 5; i++) { knives.add(knifeProvider.get()); } }

Instead of receiving a Knife instance at construction, KnifeJuggler will receive a Provider<Knife>. At this point, only the provider is injected. No actual Knife object will be injected until the get() method is called on the provider. In this case, the get() method is called five times. And since the Knife bean is a prototype, we know that the Set of knives will be given five distinct Knife objects to work it.

QUALIFYING @INJECTED PROPERTIES

@Inject

@Named("guitar")

private Instrument instrument;

 

The key difference between Spring’s @Qualifier and JSR-330’s @Named is one of semantics. Whereas @Qualifier helps narrow the selection of matching beans (using the bean’s ID by default), @Named specifically identifies a selected bean by its ID.

 

CREATING CUSTOM JSR-330 QUALIFIERS

As you can see, the only real difference between listing 3.2 and 3.1 is the import state- ment for the @Qualifier annotation. In listing 3.1 we used the one from the org.springframework.beans.factory.annotation package. But this time, we’re using the standards-friendly @Qualifier from the javax.inject package. Otherwise, they’re virtually the same.

3.2.3 Using expressions with annotation injection

@Value("Eruption")

 private String song;

As it turns out, simple values aren’t where @Value shines. Instead, @Value finds its power with SpEL expressions. Recall that SpEL lets you dynamically evaluate complex expressions, at runtime, into values to be wired into bean properties. That makes @Value a powerful wiring option.

@Value("#{systemProperties.myFavoriteSong}") private String song;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值