Spring学习总结一(续1)

9 继承bean配置

    本文上接Spring学习总结一,在平时的开发中会有子类父类,同样在bean的配置中也可以从在父bean和子bean,为了进行继承bean的学习,我们重新建一个包:com.alibaba.beans.relation。这个包里面的类分别如上文中提到过的,代码分别如下:(当然了如果没看上文的也不影响,我们只不过是为了方便,其实在这个包中的类是可以独立为一个小的demo的)。

package com.alibaba.beans.relation;

public class Address
{
	private String city;
	private String street;

	public String getCity()
	{
		return city;
	}

	public void setCity(String city)
	{
		this.city = city;
	}

	public String getStreet()
	{
		return street;
	}

	public void setStreet(String street)
	{
		this.street = street;
	}

	@Override
	public String toString()
	{
		return "Address [city=" + city + ", street=" + street + "]";
	}

}

package com.alibaba.beans.relation;

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;
	}

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

}

package com.alibaba.beans.relation;

public class Person
{
	private String name;
	private Address address;
	private Car car;

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Address getAddress()
	{
		return address;
	}

	public void setAddress(Address address)
	{
		this.address = address;
	}

	public Car getCar()
	{
		return car;
	}

	public void setCar(Car car)
	{
		this.car = car;
	}

	@Override
	public String toString()
	{
		return "Person [name=" + name + ", address=" + address + ", car=" + car + "]";
	}

}

package com.alibaba.beans.relation;

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

public class Main
{
	public static void main(String[] args)
	{
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-realtion.xml");
		
		Address address = (Address) ctx.getBean("address1");
		System.out.println("address" + address);
		
		address = (Address) ctx.getBean("address2");
		System.out.println("address2" + address);
	}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="address1" class="com.alibaba.beans.relation.Address"
		p:city="BeiJing" p:street="yangguang"></bean>
<span style="font-family:SimSun;"><!--这里的address2并没有配置class属性,也没有配置city属性,程序却可以正常运行?这是为什么尼,因为它通过parent
属性继承了address1的值,这里address1是父bean,address2是子bean --></span>
       <bean id="address2" parent="address1" p:street="wudaokou"></bean>
</beans>

总结:Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean。子 Bean 从父Bean 中继承配置, 包括 Bean 的属性配置;子 Bean 也可以覆盖从父 Bean 继承过来的配置;父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean,并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true。

10 依赖Bean配置

   如果说对于一个Person类,每一个person对象都要有一辆car,那么此时称Person依赖Car,配置依赖关系可以通过depends-on属性来指定,只需要修改上边的beans-relations.xml配置文件即可。给出代码如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="address1" class="com.alibaba.beans.relation.Address"
		p:city="BeiJing" p:street="yangguang"></bean>
	<bean id="address2" parent="address1" p:street="wudaokou"></bean>

	<bean id="car" class="com.alibaba.beans.relation.Car" p:brand="bmw"
		p:price="20000000"></bean>
	<!-- 假设在初始化每一个person的时候我们要求每人要有一辆车,此时就成为person依赖car -->
	<bean id="person" class="com.alibaba.beans.relation.Person"
		p:name="MaJie" p:address-ref="address1" depends-on="car"></bean>
</beans>

总结:Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好。如果前置依赖于多个 Bean,则可以通过逗号或空格的方式配置 Bean 的名称。

11 Bean的作用域

   Bean的作用域在默认情况下为singleton,即我们在配置文件中没有配置scope属性的时候就是默认值,在这里我们利用上面com.alibaba.beans.realtion中的类,然后新建一个beans-scope.xml,新建一个com.alibaba.beans.scope包以便写测试类Main。下面给出beans-scope.xml配置文件,和新建包下的测试类代码。

<?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.alibaba.beans.relation.Car">
		<property name="brand" value="audi"></property>
		<property name="price" value="20000000"></property>
	</bean>
</beans>

package com.alibaba.beans.scope;

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

import com.alibaba.beans.relation.Car;

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

   由于在配置文件中我们并没有申明scope,所以默认为singleton,所以测试类的输出结果为“true”,但是要是改为prototype,则测试结果就为false。下面来总结一下:

总结:在 Spring 中, 可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域. 默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域.对于scope属性的取值总结如下。

12 Spring使用外部属性

   有时我们需要在使用Spring时使用外部属性,比如我们在使用数据源时,我们先来做一个不使用外部属性的范例。首先加入C3P0和mysqljdbc的jar包。然后为了便于学习我们在类路劲下新建一个beans-properties.xml的配置文件,最后与上面讲解的一样(为了便于测试,我们新建一个Main类,它在com.alibaba.beans.properties)。下面给出在没使用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" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql:///test"></property>
	</bean>

</beans>

ackage com.alibaba.beans.properties;

import javax.sql.DataSource;

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

public class Main
{
    public static void main(String[] args) throws Exception
    {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
        DataSource ds = (DataSource) ctx.getBean("dataSource");
        
        System.out.println(ds.getConnection());
    }
}

   在实际开发中,因为对于Spring的配置文件将会很复杂,所以我们为了让开发变得更简洁、方便,我们通常会考虑使用外部属性,此时我们在类路径下新建一个名为db.properties的文件。这里先给出该文件的代码以及使用了外部属性的配置文件,然后我们去做一个小结,读者可以参看小结去理解为什么那样做。

db.properties文件:

user=root
password=123456
driverclass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///test
使用了外部属性的beans-properties.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!-- 在spring2.5之后使用下面这个标签去指定外部属性的位置 -->
	<context:property-placeholder location="classpath:db.properties" />
	<!-- 使用外部属性化文件的属性 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="driverClass" value="${driverClass}"></property>
		<property name="jdbcUrl" value="${jdbcUrl}"></property>
	</bean>

</beans>

总结:1.在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离。 2.Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量。 3.Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用。

13 SpEL

   SpEL -- Spring Expression Language. Spring的表达式语言。有关SpEL的总结,我们在代码示例完之后做一个总结。这里同样为了便于学习,新建一个包com.alibaba.beans.spel。然后在这个包下面新建以下给出代码的类和一个xml文件。在xml配置文件中我写了一点注释可以帮助理解。

package com.alibaba.beans.spel;

public class Address
{
	private String city;
	private String street;

	public String getCity()
	{
		return city;
	}

	public void setCity(String city)
	{
		this.city = city;
	}

	public String getStreet()
	{
		return street;
	}

	public void setStreet(String street)
	{
		this.street = street;
	}

	@Override
	public String toString()
	{
		return "Address [city=" + city + ", street=" + street + "]";
	}

}

package com.alibaba.beans.spel;

public class Car
{
	private String brand;
	private double price;
	private double tyrePermeter;

	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 double getTyrePermeter()
	{
		return tyrePermeter;
	}

	public void setTyrePermeter(double tyrePermeter)
	{
		this.tyrePermeter = tyrePermeter;
	}

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

}

package com.alibaba.beans.spel;

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

public class Main
{
	public static void main(String[] args)
	{
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-spel.xml");
		Address address = (Address) ctx.getBean("address");
		System.out.println(address);

		System.out.println("---------------------我是测试分割线------------------");
		Car car = (Car) ctx.getBean("car");
		System.out.println(car);

		System.out.println("------------------------我是分割线-------------------");
		Person person = (Person) ctx.getBean("person");
		System.out.println(person);
	}
}

package com.alibaba.beans.spel;

public class Person
{
	private String name;
	private Car car;
	// city引用adress bean的city属性
	private String city;
	// 根据car的price确定info:Car的price >= 300000 是金领
	// 否则是白领
	private String info;

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Car getCar()
	{
		return car;
	}

	public void setCar(Car car)
	{
		this.car = car;
	}

	public String getCity()
	{
		return city;
	}

	public void setCity(String city)
	{
		this.city = city;
	}

	public String getInfo()
	{
		return info;
	}

	public void setInfo(String info)
	{
		this.info = info;
	}

	@Override
	public String toString()
	{
		return "Person [name=" + name + ", car=" + car + ", city=" + city + ", info=" + info + "]";
	}

}
<?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.alibaba.beans.spel.Address">
		<!-- 使用SpEL表达式为属性赋一个字面值 -->
		<property name="city" value="#{'beijing'}"></property>
		<property name="street" value="WuDaoKou"></property>
	</bean>

	<bean id="car" class="com.alibaba.beans.spel.Car">
		<property name="brand" value="audi"></property>
		<property name="price" value="500000"></property>
		<!-- 使用SpEL引用类的静态属性 <div>•<span style="color:red;">调用静态方法或静态属性</span><span style="color:black;">:通过</span><span style="color:red;">T() </span><span style="color:black;">调用</span><span style="color:black;">一</span><span style="color:black;">个类的静态方法,它</span><span style="color:black;">将返回一</span><span style="color:black;">个</span><span style="color:black;">ClassObject</span><span style="color:black;">,然后再</span><span style="color:black;">调用相应的</span><span style="color:black;">方法或属性:</span></div>-->
		<property name="tyrePermeter" value="#{T(java.lang.Math).PI * 80}"></property>
	</bean>

	<bean id="person" class="com.alibaba.beans.spel.Person">
		<property name="name" value="Tom"></property>
		<!-- 使用SpEL来引用其他的bean -->
		<property name="car" value="#{car}"></property>
		<!-- 使用SpEL来引用其他bean的属性 -->
		<property name="city" value="#{address.city}"></property>
		<!-- 使用SpEL来引用选择运算符 -->
		<property name="info" value="#{car.price > 300000 ? '金领 ' : '白领'}"></property>
	</bean>
</beans>

总结:Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL。SpEL 为 bean 的属性进行动态赋值提供了便利。通过 SpEL 可以实现:

  1. 通过 bean 的 id 对 bean 进行引用;
  2. 调用方法以及引用对象中的属性;
  3. 计算表达式的值;
  4. 正则表达式的匹配。

14 IOC容器中bean的生命周期方法

   Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.Spring IOC 容器对 Bean 的生命周期进行管理的过程:(1).通过构造器或工厂方法创建 Bean 实例;(2).为 Bean 的属性设置值和对其他 Bean 的引用;(3).调用 Bean 的初始化方法;(4).Bean 可以使用了;(5).当容器关闭时, 调用 Bean 的销毁方法。在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.这里为了学习和了解IOC容器张bean的生命周期,我们同样新建一个com.alibaba.beans.cycle的包。这个包里包含Car、Main类:现给出配置文件和类的代码:

package com.alibaba.beans.cycle;

public class Car
{
	public Car()
	{
		System.out.println("Car's Constructor...");
	}

	private String brand;

	public void setBrand(String brand)
	{
		System.out.println("setBrand...");
		this.brand = brand;
	}

	public void init()
	{
		System.out.println("init...");
	}

	public void destroy()
	{
		System.out.println("destroy...");
	}
}

package com.alibaba.beans.cycle;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main
{
	public static void main(String[] args)
	{
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
		Car car = (Car) ctx.getBean("car");

		System.out.println(car);
		ctx.close();
	}
}

<?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.alibaba.beans.cycle.Car" init-method="init"
		destroy-method="destroy">
		<property name="brand" value="audi"></property>
	</bean>
</beans>

读者可以通过运行上面代码来了解IOC容器中bean的生命周期。

15 创建Bean后置处理器

   如果说我们想更细粒度的去管理bean的生命周期,我们就可以通过创建bean的后置处理器去管理。我这里先给出代码和配置文件,然后再下面做一个总结,读者可以通过代码和总结相结合去学习和理解。PS:变化的只是上面的配置文件和新添加的一个类。

package com.alibaba.beans.cycle;

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

public class MybeanProcessor implements BeanPostProcessor
{

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

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

}

<?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.alibaba.beans.cycle.Car" init-method="init"
		destroy-method="destroy">
		<property name="brand" value="audi"></property>
	</bean>
	<bean class="com.alibaba.beans.cycle.MybeanProcessor"></bean>
</beans>

读者可以通过运行结果和下面的总结去理解学习创建bean后置处理器。

总结:(1).Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.(2).Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.(3).对Bean 后置处理器而言, 需要实现BeanPostProcessor(org.springframework.beans.factory.config.BeanPostProcessor)接口. 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:


             
当添加了bean后置处理器之后,bean的生命周期为:(1).通过构造器或工厂方法创建 Bean 实例;(2).–为 Bean 的属性设置值和对其他Bean的引用;(3).将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法;(4).调用 Bean 的初始化方法;(5).将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法;(6).Bean 可以使用了;(7).当容器关闭时, 调用 Bean 的销毁方法。

    后续将继续在Spring学习总结一(续2)中进行总结,所有的代码将在总结一完结时给出下载地址。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值