4.bean的作用域和生命周期
1.作用域
以上列的book 类为例
xml
<!--提取公共bean-->
<util:list id="bookList">
<value>sd</value>
<value>dddd</value>
</util:list>
<bean id="book" class="com.xyq.spring_1.TestDemo.collectionBean.Book">
<property name="list" ref="bookList"></property>
</bean>
我们要验证默认bean是否为单例
测试类
@Test
public void test01(){
ApplicationContext context =new ClassPathXmlApplicationContext("bean2.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1.hashCode());
System.out.println(book2.hashCode());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VMSZ9Nlr-1606220500498)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201122142257908.png)]
由于我们重写了tostring,我们这边就用默认的hashcode方法来比较
我们可以看出是一样的。
所以在默认情况下 bean是单实例的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIRxkoGj-1606220500502)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201122142454551.png)]
在xml后面添加scope属性,可以看出一个是原型,一个是单例
那么我们选择单例
所以xml代码如下
<!--提取公共bean-->
<util:list id="bookList">
<value>sd</value>
<value>dddd</value>
</util:list>
<bean id="book" class="com.xyq.spring_1.TestDemo.collectionBean.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
我们再进行输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8S99PD95-1606220500504)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201122142610375.png)]
我们可以发现这次就不一样了
下面是 singleton 和 prototype的区别
-
一个是单例一个是多实例
-
设置scope=singleton 和不设置的时候默认是singleton 那么spring 就会在读取xml即
ApplicationContext context =new ClassPathXmlApplicationContext(“bean2.xml”);这一行时就创建对象
即加载的时候就会创建对象
prototype 就会在 加载的时候不创建,在getbean的时候创建。(即类似懒汉)
所以我们复习一下上面IOC的两大接口
1.BeanFactory:基本接口 spring内部开发者使用 ,懒加载,用的时候才加载
2.ApplicationContext:饿汉式加载,给应用开发者用的,是BeanFactory的子接口
我们再上面写了这么一段,我们在这边可以发现,饿汉式加载,是指加载singleton bean ,其他的bean也是懒加载
此外还有request 和seesion关键字 ,但是这两个一般不用,这是指创建后放在对应的域中
2.生命周期
生命周期分为5步
-
创建这个bean的实例(调用bean的无参构造器)
-
设置bean的属性(调用set方法)
-
调用bean的init-method(初始化)方法 (需要手动配置)
-
获取到了可用的bean,开始发挥bean的作用
-
在关闭spring容器时,会调用所配置的destroy方法 来销毁 bean实例
我们开始演示
第一步 有下面的order类
public class order { private String oName; public order() { System.out.println("第一步 调用构造方法创建bean实例"); } public void setoName(String oName) { this.oName = oName; System.out.println("第二步 调用set 方法设置bean的属性"); } public void initMethod(){ System.out.println("第三步 调用我们在xml配置的初始化方法"); } @Override public String toString() { return "第四步 获取得到了可用的bean"+"order{" + "oName='" + oName + '\'' + '}'; } public void destoryMethod(){ System.out.println("第五步 关闭容器时, 会调用我们再xml配置好的方法来销毁bean"); } }
配置xml文件
<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.xsd "> <!--工厂类--> <bean id="order" class="com.xyq.spring_1.TestDemo.Bean.order" init-method="initMethod" destroy-method="destoryMethod"> <property name="oName" value="手机"></property> </bean> </beans>
测试类
@Test
public void showBeanLife(){
ApplicationContext context =new ClassPathXmlApplicationContext("bean4.xml");
order order = context.getBean("order", com.xyq.spring_1.TestDemo.Bean.order.class);
System.out.println(order);
((ClassPathXmlApplicationContext) context).close();
}
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aw7eH68p-1606220500506)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201122150151303.png)]
3.bean的后置处理器
在第三步,调用初始化方法前后,各有一个处理器
这样算下来就有7步
第一步 调用构造方法创建bean实例
第二步 调用set 方法设置bean的属性
初始化之前,将bean传递到了后置处理器的postProcessBeforeInitialization方法处理,然后返回
第三步 调用我们在xml配置的初始化方法
初始化之后,将bean传递到了后置处理器的postProcessAfterInitialization方法处理,然后返回
第四步 获取得到了可用的beanorder{oName=‘手机’}
第五步 关闭容器时, 会调用我们再xml配置好的方法来销毁bean
接下来是演示部分, 类我们还是用order,但是我们要创建一个实现BeanPostProcessor接口的处理器类并将
其塞到容器里面发挥作用
下面是这个类的代码 它叫dealPostBean
public class dealPostBean implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前,将bean传递到了后置处理器的postProcessBeforeInitialization方法处理,然后返回");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后,将bean传递到了后置处理器的postProcessAfterInitialization方法处理,然后返回");
return bean;
}
}
xml文件
<bean id="order" class="com.xyq.spring_1.TestDemo.Bean.order"
init-method="initMethod" destroy-method="destoryMethod">
<property name="oName" value="手机"></property>
</bean>
<bean id="dealBean" class="com.xyq.spring_1.TestDemo.Bean.dealPostBean"></bean>
测试类
@Test
public void showBeanLife(){
ApplicationContext context =new ClassPathXmlApplicationContext("bean4.xml");
order order = context.getBean("order", com.xyq.spring_1.TestDemo.Bean.order.class);
System.out.println(order);
((ClassPathXmlApplicationContext) context).close();
}
5.自动装配
测试类:
@Test
public void showAutoWrie(){
ApplicationContext context =new ClassPathXmlApplicationContext("bean5.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
}
xml文件
<bean id="emp" class="com.xyq.spring_1.TestDemo.autowrie.Emp" autowire="byName">
</bean>
<bean id="dept" class="com.xyq.spring_1.TestDemo.autowrie.Dept"></bean>
类使用之前的emp和dept
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTum34pQ-1606220500509)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201122155324803.png)]
这边可以看到,对比之前的对象注入我们不再需要使用property标签,直接使用aotowire高效快捷
并且可以注意的是,autowire有 分 byname 和bytype
byname就是按照属性名称找id的
bytype 就是按照属性的类型找值 ,那么就产生一个问题了,就是同个类型用bytype就意味着你不能声明多个同样类型的bean
6.外部文件属性注入
xml
1.引入 xmlns:context=“http://www.springframework.org/schema/context” 和 http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd在声明头
2.使用<context:property-placeholder
3配置 数据库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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd ">
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
</bean>
</beans>
jdbc.properties
prop.driverClass=com.mysql.jdbc.Driver