1、Bean 的作用域
在 Spring 中, 可以在 元素的 scope 属性里设置 Bean 的作用域.
默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域
测试1:
Car.java
package com.zbiti.spring.beans.scope;
/**
* Created by slb on 2018/5/14.
*/
public class Car {
private String brand;
private double price;
public Car() {
System.out.println("Car's Constructor...");
}
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 +
'}';
}
}
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">
<!--scope值为prototype,创建容器对象之后调用getbean方法的时候调用Car的构造方法-->
<bean id="car" class="com.zbiti.spring.beans.scope.Car" scope="prototype">
<property name="brand" value="Audi"></property>
<property name="price" value="300000"></property>
</bean>
</beans>
scope指定单例还是多例。
Main.java
package com.zbiti.spring.beans.scope;
import com.zbiti.spring.beans.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by slb on 2018/5/10.
*/
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);
}
}
结果:
Car’s Constructor…
Car’s Constructor…
false
scope的值为prototype,容器对象每次调用getBean都会调用Car的构造方法。
=================================================================
测试2:
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">
<!--scope值为singleton,创建容器对象的时候调用Car的构造方法-->
<bean id="car" class="com.zbiti.spring.beans.scope.Car" scope="singleton">
<property name="brand" value="Audi"></property>
<property name="price" value="300000"></property>
</bean>
</beans>
Main.java
package com.zbiti.spring.beans.scope;
import com.zbiti.spring.beans.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by slb on 2018/5/10.
*/
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);*/ //true
}
}
结果:
Car’s Constructor…
====================================================================
2、使用外部属性文件
在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离
Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量
Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用
测试1:
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.xsd">
<!--加载数据源配置文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ssm_crud1?useSSL=false"></property>
</bean>-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
db.properties
jdbc.driverClass=com.mysql.jdbc.Driver
#数据库地址
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud1?useUnicode=true&characterEncoding=utf8
#用户名
jdbc.user=root
#密码
jdbc.password=root
#最大连接数
c3p0.maxPoolSize=30
#最小连接数
c3p0.minPoolSize=10
#关闭连接后不自动commit
c3p0.autoCommitOnClose=false
#获取连接超时时间
c3p0.checkoutTimeout=10000
#当获取连接失败重试次数
c3p0.acquireRetryAttempts=21234567891011121314151617
Main.java
package com.zbiti.spring.beans.properties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* Created by slb on 2018/5/14.
*/
public class Main {
public static void main(String args[]) throws SQLException {
<!--加载容器配置文件-->
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}
结果:
com.mchange.v2.c3p0.impl.NewProxyConnection@3891771e
===============================================================
3、表达式语言SpEl
Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言
语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL
SpEL 为 bean 的属性进行动态赋值提供了便利
通过 SpEL 可以实现
—通过 bean 的 id 对 bean 进行引用
—调用方法以及引用对象中的属性
—计算表达式的值
—正则表达式的匹配
字面量:
引用bean、 属性和方法
SpEL支持的运算符号
测试1:
beans-spel.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="address" class="com.zbiti.spring.beans.spel.Address">
<property name="city" value="#{'BeiJing'}"></property>
<property name="street" value="WuDaoKou"></property>
</bean>
<bean id="car" class="com.zbiti.spring.beans.spel.Car">
<property name="brand" value="Audi"></property>
<property name="price" value="50000"></property>
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*80}"></property>
</bean>
<!--引用其它bean的属性-->
<bean id="person" class="com.zbiti.spring.beans.spel.Person">
<property name="name" value="Tom"></property>
<property name="car" value="#{car}"></property>
<property name="city" value="#{address.city}"></property>
<property name="info" value="#{car.price > 300000 ? '金领': '白领'}"></property>
</bean>
</beans>
Address.java
package com.zbiti.spring.beans.spel;
/**
* Created by slb on 2018/5/14.
*/
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 + '\'' +
'}';
}
}
Car.java
package com.zbiti.spring.beans.spel;
/**
* Created by slb on 2018/5/14.
*/
public class Car {
private String brand;
private double price;
private double tyrePerimeter;
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 getTyrePerimeter() {
return tyrePerimeter;
}
public void setTyrePerimeter(double tyrePerimeter) {
this.tyrePerimeter = tyrePerimeter;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
", tyrePerimeter=" + tyrePerimeter +
'}';
}
}
Person.java
package com.zbiti.spring.beans.spel;
/**
* Created by slb on 2018/5/14.
*/
public class Person {
private String name;
private Car car;
private String city;
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 + '\'' +
'}';
}
}
Main.java
package com.zbiti.spring.beans.spel;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by slb on 2018/5/14.
*/
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);
}
}
结果:
====================================================================
4、Bean 的生命周期方法
Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.
Spring IOC 容器对 Bean 的生命周期进行管理的过程
—通过构造器或工厂方法创建 Bean 实例
—为 Bean 的属性设置值和对其他 Bean 的引用
—调用 Bean 的初始化方法
—Bean 可以使用了
—当容器关闭时, 调用 Bean 的销毁方法
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.
测试1:
MyBeanPostProcessor.java
package com.zbiti.spring.beans.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Created by slb on 2018/5/14.
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization:"+bean+", "+beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization:"+bean+", "+beanName);
Car car = new Car();
car.setBrand("Ford");
return car;
}
}
Car.java
package com.zbiti.spring.beans.cycle;
/**
* Created by slb on 2018/5/14.
*/
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...");
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
'}';
}
}
Main.java
package com.zbiti.spring.beans.cycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by slb on 2018/5/14.
*/
public class Main {
public static void main(String args[]){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car = (Car) ctx.getBean("car");
System.out.println(car);
}
}
结果:
Car’s Constructor…
setBrand…
postProcessBeforeInitialization:Car{brand=’Audi’}, car
init…
postProcessAfterInitialization:Car{brand=’Audi’}, car
Car’s Constructor…
setBrand…
Car{brand=’Ford’}