您的位置:首页 > 编程语言 > Java开发

Spring in action Third 4

2012-08-27 15:58 465 查看
今天阅读了本书的第二章,是关于如果进行组装Bean的基础,还有spring3新增的spel知识。

Wiring beans

2.1 Declaring beans

In our competition, we’re going to need some performers, which are defined by the Performer interface:

package com.springinaction.springidol;

public interface Performer {

void perform() throws PerformanceException;

}

2.1.1 Setting up Spring configuration

When declaring beans in XML, the root element of the Spring configuration file is the <beans> element from Spring’s beans schema. A typical Spring configuration XML file looks like this:

<?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">
<!-- Bean declarations go here -->

</beans>

2.1.2 Declaring a simple bean

2.1.3 Injecting through constructors

INJECTING OBJECT REFERENCES WITH CONSTRUCTORS

CREATING BEANS THROUGH FACTORY METHODS

<bean id="theStage"

class="com.springinaction.springidol.Stage"

factory-method="getInstance" />

2.1.4 Bean scoping

<bean id="ticket" class="com.springinaction.springidol.Ticket"scope="prototype" />

In addition to prototype, Spring offers a handful of other scoping options out of the box, as listed in table 2.2.

2.1.5 Initializing and destroying beans

To define setup and teardown for a bean, simply declare the <bean> with init- method and/or destroy-method parameters. The init-method attribute specifies a method that is to be called on the bean immediately upon instantiation.
Similarly, destroy-method specifies a method that is called just before a bean is removed from the container.

DEFAULTING INIT-METHOD AND DESTROY-METHOD

<?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-init-method="turnOnLights" default-destroy-method="turnOffLights">

...

</beans>

The default-init-method attribute sets an initialization method across all beans in a given context definition. Likewise, default-destroy-method sets a common destroy method for all beans in the context definition. In this
case, we’re asking Spring to initialize all beans in the context definition file by calling turnOnLights() and to tear them down with turnOffLights() (if those methods exist—otherwise nothing happens).

2.2 Injecting into bean properties

2.2.1 Injecting simple values

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

2.2.2 Referencing other beans

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

INJECTING INNER BEANS

<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">

<property name="song" value="Jingle Bells" />

<property name="instrument">

<bean class="org.springinaction.springidol.Saxophone" />

</property>

</bean>

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

<constructor-arg value="15" />

<constructor-arg>

<bean class="com.springinaction.springidol.Sonnet29" />

</constructor-arg>

</bean>

2.2.3 Wiring properties with Spring’s p namespace

The p namespace has a schema URI of http://www.springframework.org/ schema/p. To use it, simply add a declaration for it in the Spring XML configuration:

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

<beans xmlns=http://www.springframework.org/schema/beans

xmlns:p="http://www.springframework.org/schema/p"

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">
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist" p:song = "Jingle Bells" p:instrument-ref = "saxophone" />

2.2.4 Wiring collections

WIRING LISTS, SETS, AND ARRAYS

<bean id="hank" class="com.springinaction.springidol.OneManBand"> <property name="instruments"> <list> <ref bean="guitar" /> <ref bean="cymbal" /> <ref bean="harmonica" /> </list> </property>
</bean>

<bean id="hank" class="com.springinaction.springidol.OneManBand"> <property name="instruments"> <set> <ref bean="guitar" /> <ref bean="cymbal" /> <ref bean="harmonica" /> <ref bean="harmonica"
/> </set> </property> </bean>

WIRING MAP COLLECTIONS

<bean id="hank" class="com.springinaction.springidol.OneManBand"> <property name="instruments"> <map> <entry key="GUITAR" value-ref="guitar" /> <entry key="CYMBAL" value-ref="cymbal" /> <entry key="HARMONICA" value-ref="harmonica"
/> </map> </property> </bean>

WIRING PROPERTIES COLLECTIONS

<bean id="hank" class="com.springinaction.springidol.OneManBand"> <property name="instruments"> <props> <prop key="GUITAR">STRUM STRUM STRUM</prop> <prop key="CYMBAL">CRASH CRASH CRASH</prop> <prop key="HARMONICA">HUM HUM
HUM</prop> </props> </property> </bean>

2.2.5 Wiring nothing (null)

<property name="someNonNullProperty"><null/></property>

2.3 Wiring with expressions

So far all of the stuff we’ve wired into bean properties and constructor arguments has been statically defined in the Spring configuration XML. When we wired the name of a song into the Instrumentalist bean, that value was
determined at development time. And when we wired references to other beans, those references were also stati- cally determined while we wrote the Spring configuration.

What if we want to wire properties with values that aren’t known until runtime?

Spring 3 introduced theSpring Expression Language (SpEL),
a powerful yet succinct way of wiring values into a bean’s properties or constructor arguments using expres- sions that are evaluated at runtime. UsingSpEL,
you can pull off amazing feats of bean wiring that would be much more difficult (or even impossible) using Spring’s tradi- tional wiring style.


SpEL has a lot of tricks up its sleeves, including

¡ The ability to reference beans by their ID

¡ Invoking methods and accessing properties on objects

¡ Mathematical, relational, and logical operations on values

¡ Regular expression matching

¡ Collection manipulation

So before we can start running with SpEL, let’s take our first steps with some of the most basic ingredients of a SpEL expression.

2.3.1 Expressing SpEL fundamentals

The ultimate goal of a SpEL expression is to arrive at some value after evaluation. In the course of calculating that value, other values are considered and operated upon. The simplest kinds of values that SpEL can evaluate
may be literal values, references to a bean’s properties, or perhaps a constant on some class.

LITERAL VALUES

The simplest possible SpEL expression is one that contains only a literal value. For example, the following is a perfectly valid SpEL expression:

5

Not surprisingly, this expression evaluates to an integer value of 5. We could wire this value into a bean’s property by using #{} markers in a <property> element’s value attribute like this:

<propertyname="count"value="#{5}"/>

The
#{} markers are a clue to Spring that the content that they contain is aSpELexpression.
They
could be mixed with non-SpEL values as well:

<propertyname="message"value="Thevalueis#{5}"/>

Floating-point numbers can also be expressed in SpEL. For example:

<propertyname="frequency"value="#{89.7}"/>

Numbers can even be expressed in scientific notation. As an example, the following snippet of code sets a capacity property to 10000.0 using scientific notation:

<propertyname="capacity"value="#{1e4}"/>

Literal String values can also be expressed in SpEL with either single or double quote marks. For example, to wire a literal String value into a bean property, we could express it like this:

<propertyname="name"value="#{'Chuck'}"/>

Or if you were using single quote marks for XML attribute values, then you’d want to use double quotes in the SpEL expression:

<propertyname='name'value='#{"Chuck"}'/>

A couple of other literal values you may use are the Boolean true and false values. For example, you could express a false like this:

<propertyname="enabled"value="#{false}"/>

REFERENCING BEANS, PROPERTIES, AND METHODS

Another basic thing that a SpEL expression can do is to reference another bean by its ID.

<property name="instrument" value="#{saxophone}"/>

<bean id="carl" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="#{kenny.song}" /> </bean>

Referencing a bean’s properties isn’t the only thing you can do with a bean. You could also invoke a method.

<property name="song" value="#{songSelector.selectSong()}"/>

<property name="song" value="#{songSelector.selectSong().toUpperCase()}"/>

The way to avoid the dreaded NullPointerException in SpEL is to use the null- safe accessor:

<propertyname="song"value="#{songSelector.selectSong()?.toUpperCase()}"/>

WORKING WITH TYPES

The key to working with class-scoped methods and constants in SpEL is to use the T() operator. For example, to express Java’s Math class in SpEL, you’d need to use the T() operator like this:

T(java.lang.Math)

But the real value of the T() operator is that it gives us access to static methods and constants on a given class.

<property name="multiplier" value="#{T(java.lang.Math).PI}"/>

Similarly, static methods can also be invoked on the result of the T() operator.

<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>

2.3.2 Performing operations on SpEL values

SpEL offers several operations that you can apply on values in a SpEL expression. These operations are summarized in table 2.5.

DOING MATH WITH SPEL

SpEL supports all of the basic arithmetic operators that Java supports, plus the carat (^) operator for performing a power of operation.

<property name="adjustedAmount" value="#{counter.total + 42}"/>

<property name="adjustedAmount" value="#{counter.total - 20}"/>

<propertyname="circumference" value="#{2 *T(java.lang.Math).PI*circle.radius}"/>

<property name="average" value="#{counter.total / counter.count}"/>

<property name="remainder" value="#{counter.total % counter.count}"/>

<property name="area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>

Even though we’re talking about SpEL’s arithmetic operators, it’s worth mentioning that the + operator is overloaded to perform concatenation on String values.

<property name="fullName" value="#{performer.firstName + ' ' + performer.lastName}"/>

COMPARING VALUES

It’s often useful to compare two values to decide whether they’re equal or which is greater than the other. For that kind of comparison, SpEL offers all of the expected comparison operators that Java itself also offers.

<property name="equal" value="#{counter.total == 100}"/>

Unfortunately, the less-than and greater-than symbols pose a problem when using these expressions in Spring’s XML configuration, as they have special meaning in XML. So, when using SpEL in XML,5 it’s best to use SpEL’s textual
alternatives to these operators. For example:

<property name="hasCapacity" value="#{counter.total le 100000}"/>

LOGICAL EXPRESSIONS

It’s great that we can evaluate comparisons in SpEL, but what if you need to evaluate based on two comparisons? Or what if you want to negate some Boolean value? That’s where the logical operators come into play. Table 2.7
lists all of SpEL’s logical operators.

<property name="largeCircle" value="#{shape.kind == 'circle' and shape.perimeter gt 10000}"/>

<property name="outOfStock" value="#{!product.available}"/>

<property name="outOfStock" value="#{not product.available}"/>

CONDITIONALLY EVALUATING

<property name="instrument" value="#{songSelector.selectSong()=='Jingle Bells'?piano:saxophone}"/>

<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>

Although that’ll work, there’s a bit of duplication in that we refer to kenny.song twice. SpEL offers a variant of the ternary operator that simplifies this expression:

<propertyname="song"value="#{kenny.song?:'Greensleeves'}"/>

REGULAR EXPRESSIONS IN SPEL

When working with text, it’s sometimes useful to check whether that text matches a certain pattern. SpEL supports pattern matching in expressions with its matches operator.

The matches operator attempts to apply a regular expression (given as its right-side argument) against a String value (given as the left-side argument). The result of a matches evaluation is a Boolean value: true if the
value matches the regular expres- sion, false otherwise.

<property name="validEmail" value= "#{admin.email matches '[a-zA-Z0-9._%+-]+\\.com'%7d%22/]+@[a-zA-Z0-9.-]+\\.com'}"/>

2.3.3 Sifting through collections in SpEL

SpEL offers a few handy operators for working with collections such as this.

ACCESSING COLLECTION MEMBERS

The most basic thing we could do here is extract a single element out of the list and wire it into a property:

<propertyname="chosenCity"value="#{cities[2]}"/>

<property name="chosenCity" value="#{cities[T(java.lang.Math).random() * cities.size()]}"/>

The [] operator is also good for retrieving a member of a java.util.Map collec-tion. For example, suppose the City objects were in a Map with their name as the key. In that case, we could retrieve the entry for Dallas like
this:

<property name="chosenCity" value="#{cities['Dallas']}"/>

Another use of the [] operator is to retrieve a value from a java.util.Properties collection. For example, suppose that you were to load a properties configuration file into Spring using the <util:properties> element as
follows:

<util:propertiesid="settings" location="classpath:settings.properties"/>

Here the settings bean will be a java.util.Properties that contains all of the entries in the file named settings.properties. With SpEL, you can access a property from that file in the same way you access a member of a Map.
For example, the follow- ing use of SpEL reads a property whose name is twitter.accessToken from the settings bean:

<propertyname="accessToken"value="#{settings['twitter.accessToken']}"/>

In addition to reading properties from a <util:properties>-declared collection, Spring makes two special selections of properties available to SpEL:systemEnvironment
andsystemProperties.


systemEnvironment contains all of the environment variables on the machine run- ning the application. It’s just a java.util.Properties collection, so the square braces can be used to access its members by their key. For
example, on my MacOS X machine, I can inject the user’s home directory path into a bean property like this:

<propertyname="homePath"value="#{systemEnvironment['HOME']}"/>

Meanwhile, systemProperties contains all of the properties that were set in Java as the application started (typically using the -D argument). Therefore, if the JVM were started with -Dapplication.home=/etc/myapp, then you
could wire that value into the homePath property with the following SpEL incantation:

<propertyname="homePath"value="#{systemProperties['application.home']}"/>

Although it doesn’t have much to do with working with collections, it’s worth noting that the [] operator can also be used on String values to retrieve a single character by its index within the String. For example, the
following expression will evaluate to "s":

'This isatest'[3]

SELECTING COLLECTION MEMBERS

<property name="bigCities" value="#{cities.?[population gt 100000]}"/>

SpEL also offers two other selection operators, .^[] and .$[], for selecting the first and last matching items (respectively) from a collection.

<property name="aBigCity" value="#{cities.^[population gt 100000]}"/>

<property name="aBigCity" value="#{cities.$[population gt 100000]}"/>

PROJECTING COLLECTIONS

Collection projection involves collecting a particular property from each of the mem- bers of a collection into a new collection. SpEL’s projection operator (.![]) can do exactly that.

To get a list of just the city names, you could wire a cityNames property like this:

<propertyname="cityNames"value="#{cities.![name]}"/>

<property name="cityNames" value="#{cities.![name + ', ' + state]}"/>

<property name="cityNames" value="#{cities.?[population gt 100000].![name + ', ' + state]}"/>

I encourage you to use SpEL wherever it can simplify what would otherwise be dif- ficult (or even impossible) wirings. But be careful to not get too carried away with SpEL. Fight the temptation to put too much logic into
a SpEL expression.

相应的文档已上传,文档中包含图片。http://download.csdn.net/detail/qwewegfd/4528970
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: