`

Spring Core Tasks

 
阅读更多

1、Manage and Configure POJOs with the Spring IoC Container
  创建POPJ Class

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
    private String prefix;
    private String suffix;
    private int initial;
    private int counter;
    public SequenceGenerator() {}
    public SequenceGenerator(String prefix, String suffix, int initial) {
        this.prefix = prefix;
        this.suffix = suffix;
        this.initial = initial;
    }
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    public void setInitial(int initial) {
        this.initial = initial;
    }
    public synchronized String getSequence() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(prefix);
        buffer.append(initial + counter++);
        buffer.append(suffix);
        return buffer.toString();
    }
}

 XML配置 

 

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

	<bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
		 <property name="prefix" value="30" />
		 <property name="suffix" value="A" />
		 <property name="initial" value="100000" />
	</bean
</beans>

 实例化Spring IoC Container,并通过IoC Container创建POPJ

 

package com.apress.springrecipes.sequence;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = 
            new GenericXmlApplicationContext("beans.xml");

        SequenceGenerator generator =
            (SequenceGenerator) context.getBean("sequenceGenerator");

        System.out.println(generator.getSequence());
        System.out.println(generator.getSequence());
    }
}

 

2、Create POJOs by Invoking a Constructor

   Product.java

package com.apress.springrecipes.shop;

public abstract class Product {

    private String name;
    private double price;

    public Product() {}

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    // Getters and Setters
    public void setName(String name) { 
	this.name = name;
    }
    
    public void setPrice(double price) { 
	this.price = price;
    }

    public String getName() { 
	return name;
    }

    public double getPrice() { 
	return price;
    }

    public String toString() {
        return name + " " + price;
    }
}

 Dis.java

package com.apress.springrecipes.shop;

public class Disc extends Product {

    private int capacity;

    public Disc() {
        super();
    }

    public Disc(String name, double price) {
        super(name, price);
    }

    // Getters and Setters
    public void setCapacity(int capacity) { 
	this.capacity = capacity;
    } 
     
    public int getCapacity() { 
	return capacity;
    }
}

 Battery.java

package com.apress.springrecipes.shop;

public class Battery extends Product {

    private boolean rechargeable;

    public Battery() {
        super();
    }

    public Battery(String name, double price) {
        super(name, price);
    }

    // Getters and Setters
    public void setRechargeable(boolean rechargeable) { 
	this.rechargeable = rechargeable;
    } 
     
    public boolean getRechargeable() { 
	return rechargeable;
    }
}

 配置beans.xml

<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.2.xsd">

	<!--
		当没有constructor-arg时,调用默认构造器创建bean,否则寻找最合适的构造器;
		然后再property的属性通过setter方法初始化
	-->
	<!-- 
		Product aaa = new Battery();
		aaa.setName("AAA");
		aaa.setPrice(2.5);
		aaa.setRechargeable(true);
		
		Product cdrw = new Disc();
		cdrw.setName("CD-RW");
		cdrw.setPrice(1.5);
		cdrw.setCapacity(700);
	-->
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>
	
	<!--
		Product aaa = new Battery("AAA", 2.5);
		aaa.setRechargeable(true);
		
		Product cdrw = new Disc("CD-RW", 1.5);
		cdrw.setCapacity(700);
	-->
	<!--
		constructor-arg标签可以通过添加type属性(int、java.lang.String等)、
		name属性(形参名词)、index属性(参数顺序)等来进一步限定,进而找到最合适的构造器。
	-->
	<bean id="aaa" class="com.apress.springrecipes.shop.Battery">
		<constructor-arg value="AAA" />
		<constructor-arg value="2.5" />
		<property name="rechargeable" value="true" />
	</bean>
	
	<bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
		<constructor-arg value="CD-RW" />
		<constructor-arg value="1.5" />
		<property name="capacity" value="700" />
	</bean>
	
</beans>

     实例化

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new GenericXmlApplicationContext("beans.xml");
 
        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        System.out.println(aaa);
        System.out.println(cdrw);
    }
}

 

 3、Use POJO References, Auto-Wiring, and Imports to Interact with Other POJOs

    SequenceGenerator引用了一个PrefixGenerator 

package com.apress.springrecipes.sequence;

public interface PrefixGenerator {
    public String getPrefix();
}

 

package com.apress.springrecipes.sequence;
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.util.Date; 

public class DatePrefixGenerator implements PrefixGenerator {
    private DateFormat formatter;

    public void setPattern(String pattern) {
        this.formatter = new SimpleDateFormat(pattern);
    }

    public String getPrefix() {
        return formatter.format(new Date());
    }
}

 

package com.apress.springrecipes.sequence;

public class SequenceGenerator {
    private PrefixGenerator prefixGenerator;
    private String suffix;
    private int initial;
    private int counter;
    public SequenceGenerator() {}
    public SequenceGenerator(PrefixGenerator prefixGenerator, String suffix, int initial) {
        this.prefixGenerator = prefixGenerator;
        this.suffix = suffix;
        this.initial = initial;
    }
    public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    public void setInitial(int initial) {
        this.initial = initial;
    }
    public synchronized String getSequence() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(prefixGenerator.getPrefix());
        buffer.append(initial + counter++);
        buffer.append(suffix);
        return buffer.toString();
    }
}

     配置XML

<!-- 引用一个bean -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator">
		<property name="pattern" value="yyyyMMdd" />
    </bean>

    <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
		<property name="initial" value="100000" />
		<property name="suffix" value="A" />
		<property name="prefixGenerator" ref="datePrefixGenerator" />
	</bean>
</beans>

<!--constructor-arg 引用bean-->
<!--
<bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
	 <constructor-arg ref="datePrefixGenerator" />
	 <property name="initial" value="100000" />
	 <property name="suffix" value="A" />
</bean>
-->
	
<!-- 用一个自定义的标签p声明 -->
<!--
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator">
		<property name="pattern" value="yyyyMMdd" />
    </bean>

    <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"
        p:suffix="A" p:initial="1000000"
        p:prefixGenerator-ref="datePrefixGenerator" />
</beans>
-->

<!-- 引用内部bean-->
<!--
<bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
	 <property name="initial" value="100000" />
	 <property name="suffix" value="A" />
	 <property name="prefixGenerator">
		 <bean class="com.apress.springrecipes.sequence.DatePrefixGenerator">
			<property name="pattern" value="yyyyMMdd" />
		 </bean>
	 </property>
</bean>

<bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
	 <constructor-arg>
		 <bean class="com.apress.springrecipes.sequence.DatePrefixGenerator">
			<property name="pattern" value="yyyyMMdd" />
		 </bean>
	 </constructor-arg>
	 <property name="initial" value="100000" />
	 <property name="suffix" value="A" />
</bean>
-->

 使用bean

package com.apress.springrecipes.sequence;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = 
            new GenericXmlApplicationContext("beans.xml");

        SequenceGenerator generator =
            (SequenceGenerator) context.getBean("sequenceGenerator");

        System.out.println(generator.getSequence());
        System.out.println(generator.getSequence());
    }
}

 

 4、Configure POJOs with Java Collection Attributes

     有集合属性的POPJ Class

package com.apress.springrecipes.sequence;
import java.util.List;

public class SequenceGenerator {
    private String prefix;
    private List<Object> suffixes;
    private int initial;
    private int counter;
    public SequenceGenerator() {}
    public SequenceGenerator(String prefix, List<Object> suffixes, int initial) {
        this.prefix = prefix;
        this.suffixes = suffixes;
        this.initial = initial;
    }
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public void setSuffixes(List<Object> suffixes) {
        this.suffixes = suffixes;
    }

    public void setInitial(int initial) {
        this.initial = initial;
    }
    public synchronized String getSequence() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(prefix);
        buffer.append(initial + counter++);
	for (Object suffix : suffixes) {
            buffer.append("-");
            buffer.append(suffix);
	}
        return buffer.toString();
    }
}

 XML配置

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
	<!--
		List标签下的每一项可以是value(常量值)、ref(引用的bean)、
		idref、<bean>(匿名内部bean)、<null/>(空值);
		Set与List的唯一区别是Set中的元素不会重复,也就意味着相同的值会被覆盖
	-->
	<bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
		<property name="prefix" value="30" />
		<property name="initial" value="100000" />
		<property name="suffixes">
			<list>
				<value>A</value>
				<bean class="java.net.URL">
					<constructor-arg value="http" />
					<constructor-arg value="www.apress.com" />
					<constructor-arg value="/" />
				</bean>
				<null />
			</list>
		</property>
	</bean>
	
	<!--
	    Map的定义方式为<key>和Value
	-->
	<!--
	<bean id="sequenceGenerator"class="com.apress.springrecipes.sequence.SequenceGenerator">
		<property name="prefix" value="30" />
		<property name="initial" value="100000" />
		<property name="suffixes">
			<map>
				<entry>
					<key>
						<value>type</value>
					</key>
					<value>A</value>
				</entry>
				<entry key="type1" value="A" />
				<entry>
					<key>
						<value>url</value>
					</key>
					<bean class="java.net.URL">
						 <constructor-arg value="http" />
						 <constructor-arg value="www.apress.com" />
						 <constructor-arg value="/" />
					 </bean>
				</entry>
				<entry key="url1">
					 <bean class="java.net.URL">
						 <constructor-arg value="http" />
						 <constructor-arg value="www.apress.com" />
						 <constructor-arg value="/" />
					 </bean>
				</entry>
			</map>
		 </property>
	</bean>
	-->
	
	<!--
		Properties与Map的区别为:Properties要求键值对均为String
	-->
	<!--
	<bean id="sequenceGenerator"class="com.apress.springrecipes.sequence.SequenceGenerator">
		<property name="prefix" value="30" />
		<property name="initial" value="100000" />
		<property name="suffixes">
			<props>
				 <prop key="type">A</prop>
				 <prop key="url">http://www.apress.com/</prop>
				 <prop key="null">null</prop>
			</props>
		</property>
	</bean>
	-->
	
	<!--
		指定集合元素类型type
	-->
	<!--
	 <property name="suffixes">
		 <list>
			 <value type="int">5</value>
			 <value type="int">10</value>
			 <value type="int">20</value>
		 </list>
	 </property>
	-->
	
	<!--
		指定具体使用的集合对象,例如指定Set为TreeSet
	-->
	<!--
	<property name="suffixes">
		<bean class="org.springframework.beans.factory.config.SetFactoryBean">
			<property name="targetSetClass">
				<value>java.util.TreeSet</value>
			</property>
			<property name="sourceSet">
				<set>
					<value>5</value>
					<value>10</value>
					<value>20</value>
				</set>
			</property>
		</bean>
	</property>
	-->
	
	<!--
		指定具体使用的集合对象,例如指定Set为TreeSet,使用util标签
	-->
	<!--
	<beans xmlns="http://www.springframework.org/schema/beans"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	 xmlns:util="http://www.springframework.org/schema/util"
	 xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	 http://www.springframework.org/schema/util
	 http://www.springframework.org/schema/util/spring-util-3.2.xsd">
		 <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator">
			 <property name="prefix" value="30" />
			 <property name="initial" value="100000" />
			 <property name="suffixes">
				 <util:set set-class="java.util.TreeSet">
					 <value>5</value>
					 <value>10</value>
					 <value>20</value>
				 </util:set>
			 </property>
		 </bean>
	</beans>
	-->
</beans>

 使用bean

package com.apress.springrecipes.sequence;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = 
            new GenericXmlApplicationContext("beans.xml");

        SequenceGenerator generator =
            (SequenceGenerator) context.getBean("sequenceGenerator");

        System.out.println(generator.getSequence());
        System.out.println(generator.getSequence());
    }
}

 

5、Set a POJOs Scope

    Spring中Scope分以下几种:

    singleton -- Creates a single bean instance per Spring IoC container
    prototype -- Creates a new bean instance each time when requested
    request -- Creates a single bean instance per HTTP request; only valid in the context of a web application
    session -- Creates a single bean instance per HTTP session; only valid in the context of a web application
    globalSession -- Creates a single bean instance per global HTTP session; only valid in the context of a portalapplication

package com.apress.springrecipes.shop;

public abstract class Product {

    private String name;
    private double price;

    public Product() {}

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    // Getters and Setters
    public void setName(String name) { 
	this.name = name;
    }
    
    public void setPrice(double price) { 
	this.price = price;
    }

    public String getName() { 
	return name;
    }

    public double getPrice() { 
	return price;
    }

    public String toString() {
        return name + " " + price;
    }
}

 

 

package com.apress.springrecipes.shop;

public class Disc extends Product {

    private int capacity;

    public Disc() {
        super();
    }

    public Disc(String name, double price) {
        super(name, price);
    }

    // Getters and Setters
    public void setCapacity(int capacity) { 
	this.capacity = capacity;
    } 
     
    public int getCapacity() { 
	return capacity;
    }
}

 

package com.apress.springrecipes.shop;

public class Battery extends Product {

    private boolean rechargeable;

    public Battery() {
        super();
    }

    public Battery(String name, double price) {
        super(name, price);
    }

    // Getters and Setters
    public void setRechargeable(boolean rechargeable) { 
	this.rechargeable = rechargeable;
    } 
     
    public boolean getRechargeable() { 
	return rechargeable;
    }
}

 

package com.apress.springrecipes.shop;
import java.util.List; 
import java.util.ArrayList; 

public class ShoppingCart {

    private List<Product> items = new ArrayList<Product>();

    public void addItem(Product item) {
        items.add(item);
    }

    public List<Product> getItems() {
        return items;
    }
}

 配置XML,默认scope为singleton

<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.2.xsd">

    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" />
</beans>

 main方法,执行结果为:

Shopping cart 1 contains [AAA 2.5, CD-RW 1.5]

Shopping cart 2 contains [AAA 2.5, CD-RW 1.5, DVD-RW 3.0]

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new GenericXmlApplicationContext("beans.xml");

 
        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        Product dvdrw = (Product) context.getBean("dvdrw");

        ShoppingCart cart1 = (ShoppingCart) context.getBean("shoppingCart");
        cart1.addItem(aaa);
        cart1.addItem(cdrw);
        System.out.println("Shopping cart 1 contains " + cart1.getItems());

        ShoppingCart cart2 = (ShoppingCart) context.getBean("shoppingCart");
        cart2.addItem(dvdrw);
        System.out.println("Shopping cart 2 contains " + cart2.getItems());
    }
}

 以上shoppingCart的配置相当于:

<bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart"
   scope="singleton" />

如果shoppingCart配置为:

<bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart"
   scope="prototype" />

 main方法执行结果为:

Shopping cart 1 contains [AAA 2.5, CD-RW 1.5]

Shopping cart 2 contains [DVD-RW 3.0]

 

 2.6 Use Data from External Resources

读取java classpath路径下的properties文件,文件内容:

specialcustomer.discount=0.1
summer.discount=0.15
endofyear.discount=0.2

 在配置文件中读取properties的内容:

<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.2.xsd">

  <bean id="discountPropertyConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="location">
      <value>classpath:discounts.properties</value>
    </property>
    <property name="ignoreResourceNotFound" value="true"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
  </bean>
  
  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="discount" value="${specialcustomer.discount:0}" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="discount" value="${summer.discount:0}" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="discount" value="${endofyear.discount:0}" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />
</beans>

 也可以在java代码中读取:

public class Main {
	 public static void main(String[] args) throws Exception {
		 Resource resource = new ClassPathResource("discounts.properties");
		 Properties props = PropertiesLoaderUtils.loadProperties(resource);
		 System.out.println("And don't forget our discounts!");
		 System.out.println(props);
	}
}

 也可以直接加载某路径下的文件 或者 URL获取的文件:

Resource resource = new FileSystemResource("c:/shop/banner.txt")
Resource resource = new UrlResource("http://www.apress.com/context/banner.txt")

读取classpath下的文件:

*************************
*  Welcome to My Shop!  *
*************************

 设置一个POPJ类:

package com.apress.springrecipes.shop;

import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class BannerLoader {

    private Resource banner;

    public void setBanner(Resource banner) {
        this.banner = banner;
    }
    
    public void showBanner() throws IOException {
        InputStream in = banner.getInputStream();
	
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        while (true) {
            String line = reader.readLine();
            if (line == null)
                break;
            System.out.println(line);
        }
        reader.close();
    }
}

 初始化bean时,读取数据:

  <bean id="bannerLoader"
	class="com.apress.springrecipes.shop.BannerLoader"
	init-method="showBanner">
    <property name="banner">
      <value>classpath:banner.txt</value>
    </property>
  </bean>

 设置路径时候,还可以是:

        file:c:/shop/banner.txt

       classpath:banner.txt

       http://springrecipes.apress.com/shop/banner.txt

 

 2.7 Resolve I18N Text Messages for Different Locales in Properties Files

国际化文件:

alert.checkout=A shopping cart has been checked out.
alert.inventory.checkout=A shopping cart with {0} has been checked out at {1}.

 配置国际化文件对应的bean

<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.2.xsd">

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
     <property name="basenames">
        <list>
            <value>classpath:messages</value>
        </list>
    </property>
    <property name="cacheSeconds" value="1"/>
    </bean>

</beans>

 使用国际化:

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.Locale;
import java.util.Date;

public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context = 
            new GenericXmlApplicationContext("beans.xml");
        String alert = context.getMessage("alert.checkout", null, Locale.US);
	    String alert_inventory = context.getMessage("alert.inventory.checkout", new Object[] { "[DVD-RW 3.0]", new Date() }, Locale.US);

        System.out.println("The I18N message for alert.checkout is: " + alert);
        System.out.println("The I18N message for alert.inventory.checkout is: " + alert_inventory);
    }
}

 

 2-8. Customize POJO Initialization and Destruction

        初始化bean时的方法init-method和销毁bean时的方法destroy-method

        Product.java、Battery.java、Disc.java同上

package com.apress.springrecipes.shop;
import java.util.List; 
import java.util.ArrayList; 

public class ShoppingCart {

    private List<Product> items = new ArrayList<Product>();

    public void addItem(Product item) {
        items.add(item);
    }

    public List<Product> getItems() {
        return items;
    }
}
 
package com.apress.springrecipes.shop;

import java.io.IOException;
import java.io.File;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.util.Date;

public class Cashier {
    private String fileName;
    private String path;
    private BufferedWriter writer;

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public void openFile() throws IOException {
	File targetDir = new File(path);
	if (!targetDir.exists()) { 
	    targetDir.mkdir();
	}
        File checkoutFile = new File(path, fileName + ".txt");
	if(!checkoutFile.exists()) {
	    checkoutFile.createNewFile();
	}
        writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(checkoutFile, true)));
    }

    public void checkout(ShoppingCart cart) throws IOException {
        writer.write(new Date() + "\t" +cart.getItems() + "\r\n");
        writer.flush();
    }

    public void closeFile() throws IOException {
        writer.close();
    }
}
 配置XML
<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.2.xsd">
  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" lazy-init="true" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

    <bean id="cashier" class="com.apress.springrecipes.shop.Cashier" init-method="openFile" destroy-method="closeFile">
      <property name="fileName" value="checkout" />
      <property name="path" value="c:/Windows/Temp/cashier" />
    </bean>
</beans>
    lazy-init默认为false,如果为true,意味着,如果bean一直没有被应用初始化,那么,bean不会被初始化。

 

 初始化bean时候会执行init-method,在bean最后销毁时会执行destroy-method。

 

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new GenericXmlApplicationContext("beans.xml");


        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        Product dvdrw = (Product) context.getBean("dvdrw");

        ShoppingCart cart1 = (ShoppingCart) context.getBean("shoppingCart");
        cart1.addItem(aaa);
        cart1.addItem(cdrw);
        System.out.println("Shopping cart 1 contains " + cart1.getItems());

        ShoppingCart cart2 = (ShoppingCart) context.getBean("shoppingCart");
        cart2.addItem(dvdrw);
        System.out.println("Shopping cart 2 contains " + cart2.getItems());

	Cashier cashier = (Cashier) context.getBean("cashier");
	cashier.checkout(cart1);
	cashier.checkout(cart2);
    }
}
 

 

 如果希望一个bean初始化时比另外一个先,可以:

 

<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.2.xsd">

  <bean id="sequenceGenerator"
        class="com.apress.springrecipes.sequence.SequenceGenerator"
        autowire="byType" depends-on="datePrefixGenerator">
        <property name="initial" value="100000" />
        <property name="suffix" value="A" />
  </bean>
  
  <bean id="datePrefixGenerator" primary="true"
        class="com.apress.springrecipes.sequence.DatePrefixGenerator">
  </bean>

  <bean id="numberprefixGenerator"
        class="com.apress.springrecipes.sequence.NumberPrefixGenerator">
  </bean>

</beans>
 示例中datePrefixGenerator会比sequenceGenerator先创建。

 

2.9 Create Post Processors to Validate and Modify POJOs

     处理每个bean,可以继承BeanPostProcessor

     Product.java、Battery.java、Disc.java、Cashier.java 、ShoppingCart.java 、Main.java均同2.8例,添加如下两个类,这两个类均继承BeanPostProcessor,这意味着每个bean都会被这两个类处理,该类有两方法,一个是初始化之前处理,一个是之后。

 

package com.apress.springrecipes.shop;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class AuditCheckBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
	System.out.println("In AuditCheckBeanPostProcessor.postProcessBeforeInitialization, processing bean type: " + bean.getClass());
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}
 
package com.apress.springrecipes.shop;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class ProductCheckBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof Product) {
            String productName = ((Product) bean).getName();
	    System.out.println("In ProductCheckBeanPostProcessor.postProcessBeforeInitialization, processing Product: " + productName);
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof Product) {
            String productName = ((Product) bean).getName();
	    System.out.println("In ProductCheckBeanPostProcessor.postProcessAfterInitialization, processing Product: " + productName);
        }
        return bean;
    }
}
 在配置文件中需要配置相应的bean

 

 

<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.2.xsd">
  
    <bean class="com.apress.springrecipes.shop.ProductCheckBeanPostProcessor"/>
  
    <bean class="com.apress.springrecipes.shop.AuditCheckBeanPostProcessor"/>

    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

    <bean id="cashier" class="com.apress.springrecipes.shop.Cashier" init-method="openFile" destroy-method="closeFile">
      <property name="fileName" value="checkout" />
      <property name="path" value="c:/Windows/Temp/cashier" />
    </bean>
</beans>
 

 

2-9. Create Post Processors to Validate and Modify POJOs

       使用静态工厂方法初始化bean

 

package com.apress.springrecipes.shop;

public class ProductCreator {

    public static Product createProduct(String productId) {
        if ("aaa".equals(productId)) {
            return new Battery("AAA", 2.5);
        } else if ("cdrw".equals(productId)) {
            return new Disc("CD-RW", 1.5);
        } else if ("dvdrw".equals(productId)) {
            return new Disc("DVD-RW", 3.0);
        }
        throw new IllegalArgumentException("Unknown product");
    }
}
<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.2.xsd">
  
    <bean id="aaa" class="com.apress.springrecipes.shop.ProductCreator"
        factory-method="createProduct">
        <constructor-arg value="aaa" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.ProductCreator"
        factory-method="createProduct">
        <constructor-arg value="cdrw" />
    </bean>

    <bean id="dvdrw" class="com.apress.springrecipes.shop.ProductCreator"
        factory-method="createProduct">
        <constructor-arg value="dvdrw" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

</beans>
         通过某个bean的方法创建新的bean,例如

 

 

package com.apress.springrecipes.shop;
import java.util.Map;

public class ProductCreator {
    private Map<String, Product> products;

    public void setProducts(Map<String, Product> products) {
        this.products = products;
    }

    public Product createProduct(String productId) {
        Product product = products.get(productId);
        if (product != null) {
            return product;
        }
        throw new IllegalArgumentException("Unknown product");
    }
}
 
<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.2.xsd">
  
  <bean id="productCreator"
        class="com.apress.springrecipes.shop.ProductCreator">
        <property name="products">
            <map>
                <entry key="aaa">
                    <bean class="com.apress.springrecipes.shop.Battery">
                        <property name="name" value="AAA" />
                        <property name="price" value="2.5" />
                    </bean>
                </entry>
                <entry key="cdrw">
                    <bean class="com.apress.springrecipes.shop.Disc">
                        <property name="name" value="CD-RW" />
                        <property name="price" value="1.5" />
                    </bean>
                </entry>
                <entry key="dvdrw">
                    <bean class="com.apress.springrecipes.shop.Disc">
                        <property name="name" value="DVD-RW" />
                        <property name="price" value="3.0" />
                    </bean>
                </entry>
            </map>
        </property>
    </bean>


    <bean id="aaa" factory-bean="productCreator"
        factory-method="createProduct">
        <constructor-arg value="aaa" />
    </bean>

    <bean id="cdrw" factory-bean="productCreator"
        factory-method="createProduct">
        <constructor-arg value="cdrw" />
    </bean>

    <bean id="dvdrw" factory-bean="productCreator"
        factory-method="createProduct">
        <constructor-arg value="dvdrw" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />
</beans>
 配置中,'aaa','cdrw','dvdrw'是通过id为productCreator的bean 的createProduct方法创建的。

 

 

2-11. Use Spring Environments and Profiles to Load Different Sets of POJOs

   可以通过profile的给不同的配置加标签,然后根据实际情况激活。示例中profile分为五中:spring、summer、autumn、winter以及global,

 

<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.2.xsd">

   <beans profile="spring">  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>
   </beans>

   <beans profile="summer,winter">  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.0" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.0" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="2.5" />
        <property name="capacity" value="700" />
    </bean>
   </beans>

   <beans profile="autumn">  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>
   </beans>

   <beans profile="global">
    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

    <bean id="cashier" class="com.apress.springrecipes.shop.Cashier" init-method="openFile" destroy-method="closeFile">
      <property name="fileName" value="checkout" />
      <property name="path" value="c:/Windows/Temp/cashier" />
    </bean>
   </beans>
</beans>
 激活global和winter

 

 

package com.apress.springrecipes.shop;

import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) throws Exception {
	GenericXmlApplicationContext context = new GenericXmlApplicationContext();
	context.getEnvironment().setActiveProfiles("global","winter");
	context.load("beans.xml");
	context.refresh();

        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        Product dvdrw = (Product) context.getBean("dvdrw");

        ShoppingCart cart1 = (ShoppingCart) context.getBean("shoppingCart");
        cart1.addItem(aaa);
        cart1.addItem(cdrw);
        System.out.println("Shopping cart 1 contains " + cart1.getItems());

        ShoppingCart cart2 = (ShoppingCart) context.getBean("shoppingCart");
        cart2.addItem(dvdrw);
        System.out.println("Shopping cart 2 contains " + cart2.getItems());

	Cashier cashier = (Cashier) context.getBean("cashier");
	cashier.checkout(cart1);
	cashier.checkout(cart2);
    }
}
 也可以用java命令的参数:-Dspring.profiles.active="global,winter"来执行。也可以在Spring的Servlet的 web.xml的配置来激活:
<servlet>
  <servlet-name>dispatcher</servlet-name>
   <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
   </servlet-class>
   <init-param>
     <param-name> spring.profiles.active</param-name>
     <param-value>winter</param-value>
   </init-param>
</servlet>
 
2-12. Aspect Orientated Programming
        面向切面编程的目的:关注自身业务,分理出非自身应该做的事物,例如,安全、事物、日志等。面向切面编程中的主要概念有:
               Advice(通知):执行的操作,例如记录日志。
              JoinPoint(连接点):可以使用Advice的地方,例如每个方法前后、抛出异常时。
              PointCut(切入点):连接点可能很多,但是真正希望使用Advice的地方可能只有几个,可以用切入点来定义帅选连接点。
              Aspect(切面):切面是Advice和PointCut的结合,它是AOP的基本单元,定义了做什么(Advice)、什么时候做(方法前后或抛出异常时)、那里做(PointCut)等。
              Introduction(引入):允许向类中加入新方法、属性,即把切面引入到目标类中。
              Proxy(代理):实现AOP的机制。
              Waeving(织入):实现AOP机制的过程,Spring AOP是动态的。
   先定义一组POJO
package com.apress.springrecipes.calculator;

public interface ArithmeticCalculator {
    public double add(double a, double b);
    public double sub(double a, double b);
    public double mul(double a, double b);
    public double div(double a, double b);
}
 
package com.apress.springrecipes.calculator;

public interface UnitCalculator {
    public double kilogramToPound(double kilogram);
    public double kilometerToMile(double kilometer);
}
 
package com.apress.springrecipes.calculator;

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    public double add(double a, double b) {
        double result = a + b;
        System.out.println(a + " + " + b + " = " + result);
        return result;
    }

    public double sub(double a, double b) {
        double result = a - b;
        System.out.println(a + " - " + b + " = " + result);
        return result;
    }

    public double mul(double a, double b) {
        double result = a * b;
        System.out.println(a + " * " + b + " = " + result);
        return result;
    }

    public double div(double a, double b) {
        if (b == 0) {
            throw new IllegalArgumentException("Division by zero");
        }
        double result = a / b;
        System.out.println(a + " / " + b + " = " + result);
        return result;
    }
}
 
package com.apress.springrecipes.calculator;

public class UnitCalculatorImpl implements UnitCalculator {
    public double kilogramToPound(double kilogram) {
        double pound = kilogram * 2.2;
        System.out.println(kilogram + " kilogram = " + pound + " pound");
        return pound;
    }

    public double kilometerToMile(double kilometer) {
        double mile = kilometer * 0.62;
        System.out.println(kilometer + " kilometer = " + mile + " mile");
        return mile;
    }
}
定义切面,实现的方法中分别对应了什么时候记录日志
package com.apress.springrecipes.calculator;

import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class CalculatorLoggingAspect {
    private Log log = LogFactory.getLog(this.getClass());
    public void logBefore(JoinPoint joinPoint) {
        log.info("The method " + joinPoint.getSignature().getName()
                + "() begins with " + Arrays.toString(joinPoint.getArgs()));
    }

    public void logAfter(JoinPoint joinPoint) {
        log.info("The method " + joinPoint.getSignature().getName()
                + "() ends");
    }

    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("The method " + joinPoint.getSignature().getName()
                + "() ends with " + result);
    }

    public void logAfterThrowing(JoinPoint joinPoint,
            IllegalArgumentException e) {
        log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs())
                + " in " + joinPoint.getSignature().getName() + "()");
    }


    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("The method " + joinPoint.getSignature().getName()
                + "() begins with " + Arrays.toString(joinPoint.getArgs()));
        try {
            Object result = joinPoint.proceed();
            log.info("The method " + joinPoint.getSignature().getName()
                    + "() ends with " + result);
            return result;
        } catch (IllegalArgumentException e) {
            log.error("Illegal argument "
                    + Arrays.toString(joinPoint.getArgs()) + " in "
                    + joinPoint.getSignature().getName() + "()");
            throw e;
        }
    }
}
 日志的配置文件:
# Set root logger level to INFO and its only appender to A1.
log4j.rootLogger=INFO, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
 配置切面、切点、通知:(定义的切点为com.apress.springrecipes.calculator.ArithmeticCalculator以及com.apress.springrecipes.calculator.UnitCalculator执行的全部方法,关于切入点如何定义,可以查找更多资料)
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <aop:config>
        <aop:aspect id="loggingAspect" ref="calculatorLoggingAspect">
			<aop:pointcut id="loggingOperation" expression="within(com.apress.springrecipes.calculator.ArithmeticCalculator+) || within(com.apress.springrecipes.calculator.UnitCalculator+)" />
			<aop:before pointcut-ref="loggingOperation" method="logBefore" />
			<aop:after pointcut-ref="loggingOperation"  method="logAfter" />
			<aop:after-returning pointcut-ref="loggingOperation"  returning="result" method="logAfterReturning" />
			<aop:after-throwing pointcut-ref="loggingOperation" throwing="e" method="logAfterThrowing" />
			<aop:around pointcut-ref="loggingOperation" method="logAround" />
        </aop:aspect>
    </aop:config>

    <bean id="calculatorLoggingAspect"  class="com.apress.springrecipes.calculator.CalculatorLoggingAspect" />

    <bean id="arithmeticCalculator" class="com.apress.springrecipes.calculator.ArithmeticCalculatorImpl" />

    <bean id="unitCalculator" class="com.apress.springrecipes.calculator.UnitCalculatorImpl" />
</beans>
 main方法中没有记录日志,但是事实上记录记录了日志:
package com.apress.springrecipes.calculator;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) {

        ApplicationContext context = 
            new GenericXmlApplicationContext("beans.xml");

        ArithmeticCalculator arithmeticCalculator =
            (ArithmeticCalculator) context.getBean("arithmeticCalculator");
        arithmeticCalculator.add(1, 2);
        arithmeticCalculator.sub(4, 3);
        arithmeticCalculator.mul(2, 3);
        arithmeticCalculator.div(4, 2);

        UnitCalculator unitCalculator =
            (UnitCalculator) context.getBean("unitCalculator");
        unitCalculator.kilogramToPound(10);
        unitCalculator.kilometerToMile(5);
    }
}
2-13. Declare POJOs from Static Fields or Object Properties
静态属性构造POJO
package com.apress.springrecipes.shop;
public abstract class Product {
 public static final Product AAA = new Battery("AAA", 2.5);
 public static final Product CDRW = new Disc("CD-RW", 1.5);
 ...
}
 
<beans ...>
	 <bean id="aaa" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
		 <property name="staticField">
			<value>com.apress.springrecipes.shop.Product.AAA</value>
		 </property>
	</bean>
	<bean id="cdrw" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
		 <property name="staticField">
			<value>com.apress.springrecipes.shop.Product.CDRW</value>
		 </property>
	 </bean>
</beans>
 该配置相当于:
        Product aaa = com.apress.springrecipes.shop.Product.AAA;
        Product cdrw = com.apress.springrecipes.shop.Product.CDRW;

 还可以用如下配置

<beans xmlns="http://www.springframework.org/schema/beans"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	 xmlns:util="http://www.springframework.org/schema/util"
	 xsi:schemaLocation="http://www.springframework.org/schema/beans
		 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		 http://www.springframework.org/schema/util
		 http://www.springframework.org/schema/util/spring-util-3.2.xsd">
	 <util:constant id="aaa" static-field="com.apress.springrecipes.shop.Product.AAA" />
	 <util:constant id="cdrw" static-field="com.apress.springrecipes.shop.Product.CDRW" />
</beans>

 

 通过属性构造bean

package com.apress.springrecipes.shop;
public class ProductRanking {
    private Product bestSeller;
    public Product getBestSeller() {
         return bestSeller;
    }
    public void setBestSeller(Product bestSeller) {
        this.bestSeller = bestSeller;
   }
}

 获取bean的属性bestSeller,通过它构造一个bean:

<beans ...>
	 <bean id="productRanking" class="com.apress.springrecipes.shop.ProductRanking">
		 <property name="bestSeller">
			 <bean class="com.apress.springrecipes.shop.Disc">
				 <property name="name" value="CD-RW" />
				 <property name="price" value="1.5" />
			 </bean>
		 </property>
	 </bean>
	 <bean id="bestSeller" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
	     <property name="targetObject" ref="productRanking" />
	     <property name="propertyPath" value="bestSeller" />
	 </bean>
</beans>

 相当于Product bestSeller = productRanking.getBestSeller();

还可以如下定义:

 

<beans xmlns="http://www.springframework.org/schema/beans"
	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	 xmlns:util="http://www.springframework.org/schema/util"
	 xsi:schemaLocation="http://www.springframework.org/schema/beans
		 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		 http://www.springframework.org/schema/util
		 http://www.springframework.org/schema/util/spring-util-3.2.xsd">
	 ...
	 <util:property-path id="bestSeller" path="productRanking.bestSeller" />
</beans>

 

2-14. Making POJOs Aware of Spring’s IoC Container Resources
    Cashier将文件的路径通过path属性注入,进而访问到外部文件资源
<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.2.xsd">
  
  
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

    <bean id="cashier" class="com.apress.springrecipes.shop.Cashier" init-method="openFile" destroy-method="closeFile">
      <property name="path" value="c:/Windows/Temp/cashier" />
    </bean>
</beans>
 

 2-15. Communicate Application Events Between POJOs

      构造beans,Product.java、Battery.java、Disc.java、SoppingCart.java同上

 

package com.apress.springrecipes.shop;
import java.util.List; 
import java.util.ArrayList; 

public class ShoppingCart {
    private List<Product> items = new ArrayList<Product>();
    public void addItem(Product item) {
        items.add(item);
    }

    public List<Product> getItems() {
        return items;
    }
}
 定义Event
package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationEvent;
import java.util.Date;

public class CheckoutEvent extends ApplicationEvent {

    private Date time;
    
    public CheckoutEvent(Object source, Date time) {
        super(source);
        this.time = time;
    }

    public Date getTime() {
        return time;
    }
}

 发布Event

package com.apress.springrecipes.shop;

import java.io.IOException;
import java.io.File;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;

import java.util.Date;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

public class Cashier implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    public void setApplicationEventPublisher(
            ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void checkout(ShoppingCart cart) throws IOException {
        CheckoutEvent event = new CheckoutEvent(this, new Date());
        applicationEventPublisher.publishEvent(event);
    }
}
 监听Event.java
package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationListener;

import java.util.Date;

public class CheckoutListener implements ApplicationListener<CheckoutEvent> {
    public void onApplicationEvent(CheckoutEvent event) {
        Date time = event.getTime();

        // Do anything you like with the checkout amount and time
        System.out.println("Checkout event [" + time + "]");
    }
}

 测试Main

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new GenericXmlApplicationContext("beans.xml");

        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        Product dvdrw = (Product) context.getBean("dvdrw");

        ShoppingCart cart1 = (ShoppingCart) context.getBean("shoppingCart");
        cart1.addItem(aaa);
        cart1.addItem(cdrw);
        System.out.println("Shopping cart 1 contains " + cart1.getItems());

        ShoppingCart cart2 = (ShoppingCart) context.getBean("shoppingCart");
        cart2.addItem(dvdrw);
        System.out.println("Shopping cart 2 contains " + cart2.getItems());

	Cashier cashier = (Cashier) context.getBean("cashier");
	cashier.checkout(cart1);
	cashier.checkout(cart2);
    }
}

 每次调用checkout的时候都会发布一个事件,同时被CheckoutListener监听。

配置文件如下:(需要配置监听器的bean)

<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.2.xsd">
    
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
        <property name="rechargeable" value="true" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
        <property name="capacity" value="700" />
    </bean>

   <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
        <property name="capacity" value="700" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" scope="prototype" />

    <bean id="cashier" class="com.apress.springrecipes.shop.Cashier"/>

    <bean class="com.apress.springrecipes.shop.CheckoutListener"/>
</beans>

 

2-16. Use Property Editors in Spring

属性值与文本值之间的转换

package com.apress.springrecipes.shop;
import java.util.Date;

public class ProductRanking {

    private Product bestSeller;
    private Date fromDate;
    private Date toDate;

    ... ...
}

 

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

    <bean id="dateFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="yyyy-MM-dd" />
    </bean>

   <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <bean class="com.apress.springrecipes.shop.Disc">
                <property name="name" value="CD-RW" />
                <property name="price" value="1.5" />
            </bean>
        </property>
        <property name="fromDate">
            <bean factory-bean="dateFormat" factory-method="parse">
                <constructor-arg value="2013-09-01" />
            </bean>
        </property>
        <property name="toDate">
            <bean factory-bean="dateFormat" factory-method="parse">
                <constructor-arg value="2013-09-30" />
            </bean>
        </property>
    </bean>

    <util:property-path id="bestSeller" path="productRanking.bestSeller" />
</beans>

     示例中将2013-09-30、2013-09-1转换成了Data类型。

     采用Spring 的Property Editor

 

 

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

    <bean id="dateEditor"
        class="org.springframework.beans.propertyeditors.CustomDateEditor">
        <constructor-arg>
            <bean class="java.text.SimpleDateFormat">
                <constructor-arg value="yyyy-MM-dd" />
            </bean>
        </constructor-arg>
        <constructor-arg value="true" />
    </bean>

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date">
                    <ref local="dateEditor" />
                </entry>
            </map>
        </property>
    </bean>

    <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <bean class="com.apress.springrecipes.shop.Disc">
                <property name="name" value="CD-RW" />
                <property name="price" value="1.5" />
            </bean>
        </property>
        <property name="fromDate" value="2013-10-01" />
        <property name="toDate" value="2013-10-31" />
    </bean>

    <util:property-path id="bestSeller" path="productRanking.bestSeller" />
</beans>

 配置中,CustomEditorConfigure中注册了键值对,key是要转换成的对象,value是PropertyEditor(转换规则),然后再property中就会自动识别。

也可以自定义转换规则:

package com.apress.springrecipes.shop;

import java.beans.PropertyEditorSupport;

public class ProductEditor extends PropertyEditorSupport {

    public String getAsText() {
        Product product = (Product) getValue();
        return product.getClass().getName() + "," + product.getName() + ","
                + product.getPrice();
    }

    public void setAsText(String text) throws IllegalArgumentException {
        String[] parts = text.split(",");
        try {
            Product product = (Product) Class.forName(parts[0]).newInstance();
            product.setName(parts[1]);
            product.setPrice(Double.parseDouble(parts[2]));
            setValue(product);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }
}

 定义的key为Product,value为ProductEditor,

 <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date">
                    <ref local="dateEditor" />
                </entry>
                <entry key="com.apress.springrecipes.shop.Product">
                    <bean class="com.apress.springrecipes.shop.ProductEditor" />
                </entry>
            </map>
        </property>
    </bean>

    <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <value>com.apress.springrecipes.shop.Disc,CD-RW,1.5</value>
        </property>
        <property name="fromDate" value="2013-12-01" />
        <property name="toDate" value="2013-12-31" />
    </bean>

 

2-22. Use the Spring Expression Language to Configure POJOs

 

package com.apress.springrecipes.spel;

import java.util.Properties;

public class CommonData { 

    private Properties commonProperties;
    private String userOS;
    private String userRegion;
    private double randomNumber; 
    private String email;

    public Properties getCommonProperties() { 
	return commonProperties;
    }

    public String getUserOS() { 
	return userOS;
    }

    public String getUserRegion() { 
	return userRegion;
    }
    
    public double getRandomNumber() { 
	return randomNumber;
    }

    public String getEmail() { 
	return email;
    }

    public void setCommonProperties(Properties commonProperties) { 
	this.commonProperties = commonProperties; 
    }

    public void setUserOS(String userOS) { 
	this.userOS = userOS;
    }

    public void setUserRegion(String userRegion) { 
	this.userRegion = userRegion;
    }

    public void setRandomNumber(double randomNumber) { 
	this.randomNumber = randomNumber;
    }

    public void setEmail(String email) { 
	this.email = email;
    }
}
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="commonData"
        class="com.apress.springrecipes.spel.CommonData"
	p:commonProperties="#{@systemProperties}"
	p:userOS="#{@systemProperties['os.name']?:'unknown OS'}"
	p:userRegion="#{@systemProperties['user.region']?:'unknown region'}"
	p:randomNumber="#{  T(java.lang.Math).random() * 100.0 }"
        p:email="#{emailUtilities.email}"/>
</beans>

     示例中,XML使用SpeL

<bean id="emailUtilities" class="com.apress.springrecipes.spel.EmailUtilities"
     p:email="webmaster@acme.org"
     p:password="springrecipes"
     p:host="localhost:25"/>
<bean id="commonData"
     ...
   p:email="#{emailUtilities.email}"/>

 示例中,commonData使用了emailUtilities的属性的值。

    也可以在代码中使用SpeL

package com.apress.springrecipes.spel;
...
@Component
public class CommonData {
     @Value("#{systemProperties}")
     private Properties commonProperties;
     @Value("#{systemProperties['os.name']?:'unknown OS'}")
     private String userOS;
     @Value("#{systemProperties['user.region']?:'unknown region'}")
     private String userRegion;
   //Setter & getter methods omitted
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics