一、Bean生命周期
生命周期:即Bean从初始化到销毁的整个过程 在Tesla实体中增加两个方法,初始化方法和销毁方法
public class Tesla { private String name; private String battery; // 电池 private String engine; // 电机 private String chassis; //底盘 private String bodywork; // 车身 private String owner; // 车主 public void init(){ System.out.println(this.getClass().getName() + "init方法被调用"); } public void destroy(){ System.out.println(this.getClass().getName() + "destroy方法被调用"); } // 此处省略getter/setter/toString方法 } 复制代码
在bean_life_cycle.xml中配置Tesla,初始化方法使用init-method属性表示,销毁方法使用destroy-method表示
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:p = "http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <bean id="tesla" class="com.citi.entity.Tesla" init-method="init" destroy-method="destroy"> <property name="name" value="tesla"></property> <property name="owner" value="musk"></property> </bean> </beans> 复制代码
新增测试类BeanLifeCycleTest,增加测试方法
public class BeanLifeCycleTest { @Test public void testGetBean(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean_life_cycle.xml"); System.out.println("IoC容器创建完成"); Tesla tesla = context.getBean("tesla",Tesla.class); System.out.println(tesla); context.close(); } } 复制代码
控制台打印,初始化方法和销毁方法都被调用
修改xml中Bean的配置为多实例
<bean id="tesla" scope="prototype" class="com.citi.entity.Tesla" init-method="init" destroy-method="destroy"> <property name="name" value="tesla"></property> <property name="owner" value="musk"></property> </bean> 复制代码
执行测试方法,控制台打印如下,多实例情况下只会调用初始化方法,不会调用销毁方法
- 多实例获取Bean的时候才会调用初始化方法,容器关闭不会调用destroy方法
- 单实例容器创建完成之前会调用初始化方法,Bean会在容器创建前创建,容器关闭时会调用Bean的destroy方法
Bean的后置处理器
BeanPostProcessor后置处理器接口可以定义Bean初始化前后执行的方法,新增config包,增加自定义的BeanPostProcessor
public class CustBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + "初始化前调用该方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + "初始化后调用该方法"); return bean; } } 复制代码
在bean_life_cycle.xml增加CustBeanPostProcessor的xml配置,再增加一个 Person实体类的bean xml配置
<bean id="stark" class="com.citi.entity.Person"> <property name="lastName" value="stark"></property> </bean> <bean class="com.citi.config.CustBeanPostProcessor"></bean> 复制代码
执行测试方法,每个Bean初始化前后都调用了后置处理器,后置处理器对容器中的每一个Bean都起作用
管理连接池及引用外部配置文件
以数据库连接池为例,数据库连接池最好是单例模式的,一个连接池中有多个数据库连接.
使用Spring Bean配置文件创建和管理数据库连接池
首先增加数据驱动及连接池的依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.14</version> </dependency> 复制代码
在connection_config.xml中增加数据库连接池的配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="initialSize" value="5"/> <property name="maxActive" value="20"/> </bean> 复制代码
增加测试类
public class JdbcConnectionTest { @Test public void testGetBean() throws SQLException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:connection_config.xml"); System.out.println("IoC容器创建完成"); DruidDataSource dataSource = context.getBean("dataSource",DruidDataSource.class); System.out.println(dataSource); System.out.println(dataSource.getConnection()); } } 复制代码
数据库连接被成功创建
引用外部配置文件
在resources目录下创建数据库信息配置文件datasource.properties
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username=root password=root initialSize=5 maxActive=20 复制代码
修改connect_config.xml中的配置,增加引用外部配置文件的配置,并修改连接池的配置
<!--引用外部配置文件--> <context:property-placeholder location="classpath:database.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}" /> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <property name="initialSize" value="${initialSize}"/> <property name="maxActive" value="${maxActive}"/> </bean> 复制代码
执行测试方法,成功获取数据库连接
基于XML的自动装配
在之前章节中为各种属性正确赋值都是通过property标签进行手动赋值,使用bean标签中的autowire属性可以设置自动赋值,autowire配置的含义
- default:不自动装配,默认配置
- byName:以属性名作为ID进行赋值
- byType: 按照类型进行自动赋值,如果有多个相同类型的Bean在容器中会会报错
- constructor: 使用有参构造器进行赋值,先按照够再起的参数类型进行装配,如果容器中不存在car,直接赋值null,存在多个使用属性名作为区分
byName
在autowire.xml中增加配置
<bean id="car" class="com.citi.entity.Car"> <property name="carName" value="JAUGAR"></property> <property name="color" value="英国绿"></property> <property name="price" value="580000"></property> </bean> <bean id="stark" class="com.citi.entity.Person" autowire="byName"> <property name="lastName" value="stark"></property> </bean> 复制代码
Person实体类中有一个属性名为car,autowire使用byName配置可以自动将容器id为car的Bean自动赋值为Person
增加测试类AutowireBeanTest,测试方法testGetBean()
public class AutowireBeanTest { @Test public void testGetBean(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:autowire.xml"); System.out.println("IoC容器创建完成"); Person stark = context.getBean("stark",Person.class); System.out.println(stark); } } 复制代码
已成功将容器中的car自动装配的Person中的car,如果容器中不存在car,则无法自动赋值,Person bean中的car属性为null
byType
将xml配置中的byName改为byType,再次执行测试,可以将Person实体类中的Car属性及Map中的Car属性都自动装配上以及一些环境变量
如果容器中有多个Car,在xml中多配置一个Car Bean标签,执行测试
constructor
Person实体类中增加只包含Car的有参构造器
public Person(Car car) { System.out.println("只包含Car的有参构造器被调用"); this.car = car; } 复制代码
autowire.xml中只保留一个car的xml配置,将person的xml配置中的autowire属性改为constructor,执行测试方法
如果存在多个car bean,增加一个car配置
<bean id="car01" class="com.citi.entity.Car"> <property name="carName" value="F-Type"></property> <property name="color" value="英国绿"></property> <property name="price" value="580000"></property> </bean> 复制代码
执行测试,成功赋值name为JAUGAR的car,当存在多个同类型的Bean时,优先按照属性名进行自动赋值
自动装配即自动赋值
Spring 表达式 (SpEL)
使用#{}表示Spring 表达式
- 支持使用字面量
- 支持引用其他Bean及Bean的属性
- 支持调用静态及非静态方法
- 支持所有的运算符 xml配置文件中修改Person xml配置
<bean id="stark" class="com.citi.entity.Person" autowire="constructor"> <property name="lastName" value="stark"></property> <property name="age" value="#{1*3*4*5}"></property> <property name="car" value="#{car}"></property> <!--调用静态方法--> <property name="email" value="#{T(java.util.UUID).randomUUID().toString().substring(0,5)}"></property> <property name="gender" value="#{car.getCarName()}"></property> </bean> 复制代码
执行测试方法,各属性使用EL表达式成功赋值