Spring框架自学之路(四)

(04Day)

        今天我们来看看spring提供的表达式语言spel, Bean的生命周期以及前面提到过的通过工厂方法创建Bean。

    (1)SpEL表达式语言

         SpEL是一个支持运行时查询和操作对象的表达式语言。

         SpEL语法类似于EL表达式语言,SpEL使用#{…} 作为界定符。SpEL为bean属性进行动态赋值提供了方便。

          通过 SpEL 可以实现:

           1)通过 bean 的 id 对 bean 进行引用

           2)调用方法以及引用对象中的属性

           3)计算表达式的值

           4)正则表达式的匹配

            下面通过一段代码来说明

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

	<bean id="address" class = "com.spel.Address">
		<!-- 通过spel为bean的属性赋字面值 -->
		<property name="city" value="#{'厦门'}"></property>
		<property name="street" value="集美区"></property>
	</bean>
	<bean id = "car" class="com.spel.Car">
		<property name="brand" value="奥迪"></property>
		<property name="price" value="600000"></property>
		<!-- 通过spel的T引用类的静态属性 -->
		<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*88}"></property>
	</bean>
	<bean id="person" class="com.spel.Person">
		<property name="name" value="张三"></property>
		<property name="city" value="#{address.city}"></property>
		<property name="car" value="#{car}" ></property>
		<!-- 使用spel中的运算符 -->
		<property name="info" value="#{car.price>300000 ? '金领' : '白领'}"></property>
	</bean>
</beans>

    (2)Bean的生命周期

        说到生命周期我们会想到Tomcat容器也就是servlet容器的生命周期,其实Bean的生命周期和servlet的容器的生命周期类似。在IOC容器中对Bean的生命周期管理过程如下:

  1. 首先通过构方法或者工厂方法创建Bean实例,也就是说首先执行构造方法或者工厂方法。
  2. 再通过set方法等为Bean的属性赋值和对其他Bean的引用。
  3. 调用Bean的初始化方法,初始化方法为自己定义的方法,需要要spring配置文件中设置init-method=“你定义的初始化方法”。
  4. 此时Bean就创建成功。
  5. 当容器关闭时,调用Bean的销毁方法,和初始化方法一样,销毁方法需要自己定义且需要在spring配置文件中设置destroy-method=“你定义的销毁方法”。    

        在spring中还提供了Bean的后置管理器。Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理(有点像拦截器)Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理,而非单一实例. 其典型应用是:检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。

        对Bean的后置处理器而言,需要实现BeanPostProcessor接口。添加了Bean的后置处理器后其生命周期变为如下:

  1. 通过构造方法创建Bean的实例。
  2. 为Bean的属性赋值和对其他Bean的引用。
  3. 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法。
  4. 调用Bean的初始化方法
  5. 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法。
  6. Bean创建成功
  7. 当IOC容器关闭的时候,调用Bean的销毁方法

         下面我们来看个例子:

首先创建个Car类。   

package com.cycle;

public class Car {
	private String brand;

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public Car(String brand) {
		super();
		this.brand = brand;
	}

	public Car() {
		System.out.println("Car is Constructor");
	}
	public void init2(){
		System.out.println("init.....");
	}
	public void destroy(){
		System.out.println("destroy.......");
	}

	@Override
	public String toString() {
		return "Car [brand=" + brand + "]";
	}
	
}

创建MyBeanPostProcessor类

package com.cycle;

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

public class MyBeanPostProcessor implements BeanPostProcessor {

	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("postProcessAfterInitialization "+bean+","+beanName);
		return bean;
	}

	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("postProcessBeforeInitialization "+bean+","+beanName);
		return bean;
	}

}

创建spring配置文件

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

	<bean id = "car" class="com.cycle.Car" 
		init-method="init2" destroy-method="destroy" >
		<property name="brand" value="奔馳"></property>
	</bean>
	<!-- 类实现BeanPostProcessor接口,并且提供
		 public Object postProcessAfterInitialization(Object bean, String beanName):init-method之前被调用
		 public Object postProcessBeforeInitialization(Object bean, String beanName)init-method之后被调用
		 bean属性:bean 实例本身
		 beanName属性:IOC容器中配置Bean的名字
		 返回值:实际上是用来返回给用户的那个bean,注意:可以在上述两个方法中修改返回的bean,甚至返回一个新的bean
	 -->
	<!-- 配置Bean后置处理器  不需要配置id,IOC容器会自动识别一个BeanPostProcessor
		  注意:所有的bean创建都会经过配置的后置处理器。
	-->
	<bean class="com.cycle.MyBeanPostProcessor"></bean>
</beans>

最后创建个测试类

package com.cycle;


import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main9 {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
		Car car = (Car)ctx.getBean("car");
		System.out.println(car);
		//将ctx转换成ClassPathXmlApplicationContext类型才能执行关闭容器的操作。
		ctx.close();
	}

}

    (3)通过工厂方法创建Bean

        通过工厂方法创建Bean有三种形式分别为通过静态工厂方法创建Bean、通过实例工厂方法创建Bean和实现FactoryBean接口在IOC容器中配置Bean。下面我们逐一看看这些方法该如何使用。

            3-1静态工厂方法

    调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中。 当客户端需要对象时,,只需要简单地调用静态方法, 而不同关心创建对象的细节。静态工厂方法和字面上意思一样在spring配置文件中不需要创建静态工厂方法的实例,只需要在配置实例的时候Class路径指向静态工厂方法的全类名,切在Bean的配置元素中添加factory-method=“你要执行的静态方法”。如果静态方法有参数要传入那么可以通过Bean的子元素<constructor-arg value="属性值"></constructor-arg>来逐一设置。

            3-2实例工厂方法

    实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里.。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节。和静态工厂方法不一样的地方在使用实例工厂方法的时候需要先在spring配置文件中创建出一个实例工厂方法的实例。在需要用到实例工厂方法的Bean中factory-bean="你创建的实例工厂方法的名字"来指定使用哪个实例工厂方法,再通过factory-method="你要执行的方法"来调用你要执行的工厂方法。如果该方法有参数和静态工厂方法一样通过constructor-arg来传入参数。

    下面我来看个例子如何使用这两个方法来创建Bean。

首先创建一个Car类

package com.factory;

public class Car {
	private String brand;
	private double price;
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Car(String brand, double price) {
		super();
		this.brand = brand;
		this.price = price;
	}
	public Car() {
		super();
	}
	@Override
	public String toString() {
		return "Car [brand=" + brand + ", price=" + price + "]";
	}
	
}

创建静态工厂

package com.factory;

import java.util.HashMap;
import java.util.Map;

public class StaticCarFactory {
	private static Map<String,Car> cars = new HashMap<String,Car>();
	static{
		cars.put("奥迪", new Car("奥迪",400000));
		cars.put("奔驰", new Car("奔驰",600000));
	}
	public static Car getCar(String name){
		return cars.get(name);
	}
}

创建实例工厂

package com.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 实例工厂方法;既需要创建工厂本身,再通过工厂的实例方法来返回bean的实例。
 * @author User
 *
 */
public class InstanceCarFactory {
	private Map<String,Car> cars = null;
	public InstanceCarFactory(){
		cars = new HashMap<String, Car>();
		cars.put("奥迪", new Car("奥迪",400000));
		cars.put("奔驰", new Car("奔驰",600000));
	}
	public Car getCar(String brand){
		return cars.get(brand);
	}
}

创建spring配置文件

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

	<!-- 通过静态工厂方法来配置Bean 注意不是配置静态工厂方法的实例,而是配置bean的实例 
		 class:指向静态工厂方法的全类名
		 factory-method="getCar" 指向静态工厂方法名。
		 constructor-arg:如果工厂方法需要传入参数,则通过constructor-arg类配置对应的参数
	-->
	<bean id="car1" class="com.factory.StaticCarFactory"
	factory-method="getCar">
		<constructor-arg value="奥迪"></constructor-arg>
	</bean>
	<!-- 配置工厂的实例 -->
	<bean id="carFactory" class="com.factory.InstanceCarFactory"></bean>
	<bean id="car2" factory-bean="carFactory" factory-method="getCar">
		<constructor-arg value="奔驰"></constructor-arg>
	</bean>
</beans>

最后做个测试

package com.factory;

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

public class Main10 {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");
		Car car1 = (Car)ctx.getBean("car1");
		System.out.println(car1);
		Car car2 = (Car)ctx.getBean("car2");
		System.out.println(car2);
	}

}

            3-3通过实现FactoryBean接口创建Bean

    Spring 中有两种类型的 Bean,一种是普通Bean, 另一种是工厂Bean, 即FactoryBean。工厂 Bean 跟普通Bean不同,其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象。话不多说来看个例子就能明白什么是FactoryBean。

创建个Car类 

package com.factorybean;

public class Car {
	private String brand;
	private double price;
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Car(String brand, double price) {
		super();
		this.brand = brand;
		this.price = price;
	}
	public Car() {
		super();
	}
	@Override
	public String toString() {
		return "Car [brand=" + brand + ", price=" + price + "]";
	}
	
}

创建FactoryBean用来配置Car

package com.factorybean;

import org.springframework.beans.factory.FactoryBean;


public class CarFactoryBean implements FactoryBean<Car> {
	private String brand;
	/* 返回Bean的对象
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	public Car getObject() throws Exception {
		return new Car(brand,500000);
	}
	
	/* 返回bean的类型
	 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
	 */
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Car.class;
	}

	/* 是否单例
	 * @see org.springframework.beans.factory.FactoryBean#isSingleton()
	 */
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}
	
}

创建spring配置文件

<?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.xsd">
	<!-- 通过factoryBean来配置Bean的实例
		 class:指向Factory的全类名
		 property配置factoryBean的属性
		 实际上是返回的实例是FactoryBean的getObject()方法返回的实例。
	 -->
	<bean id="car" class="com.factorybean.CarFactoryBean">
		<property name="brand" value="宝马"></property>
	</bean>
</beans>

最后写给测试类

package com.factorybean;

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

public class Main11 {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factorybean.xml");
		Car car = (Car)ctx.getBean("car");
		System.out.println(car);
	}

}

猜你喜欢

转载自blog.csdn.net/qq_38166944/article/details/79828641