bean的一些处理东西
本节我们要讲一下在bean的一些额外配置以及一些额外处理等等的东西。
util名称空间
作用是创建集合类型的bean,方便他人的引用!
1、加入util名称空间
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
2、使用
<util:map id="misiai_map">
<!--一个entry就代表一个键值对-->
<entry key="key01" value="迷思爱"/>
<entry key="key02" value="学习乐园"/>
<!--引用外部的bean 的 id-->
<entry key="key03" value-ref="book01"/>
<!--内部bean-->
<entry key="key04">
<bean class="com.misiai.bean.Car">
<property name="name" value="奔驰"/>
<property name="color" value="银色"/>
</bean>
</entry>
</util:map>
<bean id="student03" class="com.misiai.bean.Student">
<property name="map" ref="misiai_map"/>
</bean>
3、测试
@Test
public void test03() {
Student student03 = ap.getBean("student03", Student.class);
System.out.println(student03.getMap());
}
Tips:
上面我们只是举了map的例子,其实util还有其他许多的类型:
级联属性
<bean id="student04" class="com.misiai.bean.Student">
<!--引用赋值的时候,顺带改变car的价格-->
<property name="car" ref="car"/>
<property name="car.price" value="50000"/>
</bean>
@Test
public void test04() {
Student student04 = ap.getBean("student04", Student.class);
System.out.println(student04.getCar());
}
结果:
但是,由于是引用,那么原来的bean的值可能被覆盖:
@Test
public void test04() {
Student student04 = ap.getBean("student04", Student.class);
Car car = ap.getBean("car", Car.class);
System.out.println(car.getPrice());
System.out.println(student04.getCar());
}
Bean信息的重用
通过parent
来引用父级的bean的一些信息:
<!--bean信息的重用-->
<bean id="student05" class="com.misiai.bean.Student">
<property name="name" value="Misiai"/>
<property name="sno" value="10003"/>
</bean>
<bean id="student06" class="com.misiai.bean.Student" parent="student05">
<!--parent代表要继承的Bean的信息-->
<property name="sno" value="10004"/>
<!--要改变的就还是在这里填写,不改的就忽略!-->
</bean>
测试:
@Test
public void test05() {
Student student05 = ap.getBean("student05", Student.class);
Student student06 = ap.getBean("student06", Student.class);
System.out.println(student05);
System.out.println("student06 = " + student06);
}
结果:
学号改了,姓名没改!
我们还可以为一个bean设置abstract="true"
属性,代表该bean只能被继承,不能被使用!
<!--bean信息的重用-->
<bean id="student05" class="com.misiai.bean.Student" abstract="true">
<property name="name" value="Misiai"/>
<property name="sno" value="10003"/>
</bean>
如果加了abstract
,那么还尝试获取的话,就会有异常:
org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'student05': Bean definition is abstract
bean之间的依赖
A. 默认
这里我们新建spring-ioc-3.xml
配置文件,新建三个bean:
<bean id="student01" class="com.misiai.bean.Student">
</bean>
<bean id="car01" class="com.misiai.bean.Car">
</bean>
<bean id="book01" class="com.misiai.bean.Book">
</bean>
也新建一个测试类,Test03.java
在三个实体类的无参构造器中,各打印一句话:XX被创建了!
测试:
@Test
public void test01() {
Student student = (Student) ap.getBean("student01");
Car car01 = ap.getBean("car01", Car.class);
Book book01 = ap.getBean("book01", Book.class);
}
看其先后顺序:
结论:
按照配置的顺序创建的!
B. 有依赖(改变顺序)
<bean id="student01" class="com.misiai.bean.Student" depends-on="car01,book01">
</bean>
<bean id="car01" class="com.misiai.bean.Car">
</bean>
<bean id="book01" class="com.misiai.bean.Book">
</bean>
使用depends-on
,添加依赖,多个依赖英文,分割,传入的是其他 bean的id
结果:
创建单实例和多实例*
bean的默认是单实例的,我们可以为bean标签添加一个scope
属性,其值代表是单实例还是多实例。
可取的值:
- prototype,多实例
- 容器启动时,不创建
- 获取的时候再创建,且创建的是新的
- singleton,单实例(默认)
- 在容器启动之前,则已经被创建了
- 任何时候的获取都是获取之前创建好了的
- request,web环境下,同一次请求创建一个bean(真实环境中,基本不用)
- session,web环境下,同一次会话创建一个bean(真实环境中,基本不用)
测试:给car加一个prototype
<bean id="car01" class="com.misiai.bean.Car" scope="prototype">
</bean>
@Test
public void test01() {
// Student student = (Student) ap.getBean("student01");
// Book book01 = ap.getBean("book01", Book.class);
Car car01 = ap.getBean("car01", Car.class);
Car car02 = ap.getBean("car01", Car.class);
System.out.println(car01 == car02);
}
结果:
创建有生命周期的bean
1、修改Book实体类,增加两个方法
public void myInit() {
System.out.println("Book的初始化方法");
}
public void myDestroy() {
System.out.println("Book的销毁方法");
}
2、修改配置 文件
<bean id="book01" class="com.misiai.bean.Book"
init-method="myInit" destroy-method="myDestroy">
</bean>
在标签中使用init-method
和destroy-method
属性,属性值就是刚才新建的方法名。
3、测试
public class Test04 {
ApplicationContext ap = new ClassPathXmlApplicationContext("spring-ioc-4.xml");
@Test
public void test01() {
// Book book01 = ap.getBean("book01", Book.class);
// System.out.println(book01);
}
}
这里我们什么都不做,然后只是创建了容器,运行结果:
结论:只是执行了初始化方法(说明容器未销毁)
4、测试2
我们使用另一个Context对象,来测试(该对象有容器的close方法)
public class Test04 {
ConfigurableApplicationContext ap = new ClassPathXmlApplicationContext("spring-ioc-4.xml");
@Test
public void test01() {
ap.close();
}
}
结果:
Bean的后置处理器
1、实现PostProcessor类
MyBeanPostProcessor.java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "Processor之前");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "Processor之前");
return bean;
}
}
2、将此类定义到一个Bean中
<bean id="book01" class="com.misiai.bean.Book"
init-method="myInit" destroy-method="myDestroy">
</bean>
<bean class="com.misiai.bean.MyBeanPostProcessor" id="beanPostProcessor"/>
3、测试
/**
* 测试后置处理器
*/
@Test
public void test03() {
Book book01 = ap.getBean("book01", Book.class);
}
结果:
结论:在某个类的初始化之前执行一次,之后执行一次。
那我们可以调用该处理器执行一些动作!
其具体流程:
容器启动 --- 后置处理器Before --- bean的初始化方法 --- 后置处理器After --- bean初始化完成
引用外部属性文件*
在某些地方,单实例是非常最重要的!比如:数据库的连接池
这里来讲一下如何使用spring管理我们的数据库连接池!
1、导包
A. durid:https://mvnrepository.com/artifact/com.alibaba/druid/1.1.21
可自行从上面链接下载 jar包!
2、新建配置文件
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="url" value="jdbc:mysql://localhost:3306/java_test"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="5"/>
<property name="minIdle" value="5"/>
<property name="maxActive" value="100"/>
</bean>
3、新建测试类
public class Test05 {
ConfigurableApplicationContext ap = new ClassPathXmlApplicationContext("spring-ioc-5.xml");
/**
* 测试数据库
*/
@Test
public void test01() throws SQLException {
// 1、从容器中拿到连接池
DataSource dataSource = ap.getBean("dataSource", DataSource.class);
System.out.println(dataSource);
}
}
结果:
连接成功,我们这里就使用spring帮我们管理数据库连接池,然后数据库连接池使用的是druid(阿里开源维护的)!
但是有个问题,连接信息我们是写死了在xml配置文件里面的,那么如何写到外部呢?
步骤1:
新建jdbc.properties
文件
jdbc.url=jdbc:mysql://localhost:3306/java_test
jdbc.username=root
jdbc.password=root
jdbc.initialSize=5
jdbc.minIdle=5
jdbc.maxActive=100
步骤2:使用PropertyPlaceholderConfigurer
类,引入jdbc.properties文件,然后在需要的地方使用${jdbc.username}获取
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
</bean>
结果没问题!