7.9 容器中Bean的生命周期

      Spring可以管理singleton作用域的Bean的生命周期,Spring可以精确地知道该Bean何时被创建,何时被初始化完成、容器何时准备销毁该Bean实例。

      对于prototype作用域的Bean,Spring容器仅仅负责创建,当容器创建了Bean实例之后,Bean实例完全交给容器代码管理,容器不再跟踪其声明周期。每次客户端情i去prototype作用域的Bean时,Spring都会残生一个新的实例。

      对于singleton作用域的Bean,Spring可以管理实例化结束之后和销毁之前的行为。

      管理Bean的声明周期行为主要有:注入依赖关系之后;即将销毁Bean之前;

      7.9.1 依赖关系注入之后的行为

        Spring提供来年各种方式在Bean全部属性设置成功后执行特定行为。

        ⊙ 实现InitalizingBean接口。(先与init-method属性指定的初始化方法执行)(void afterPropertiesSet() throws Exception;)

        ⊙ 使用init-method属性

        Class : Chinese

package edu.pri.lime._7_9_1.bean.impl;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import edu.pri.lime._7_9_1.bean.Axe;
import edu.pri.lime._7_9_1.bean.Person; public class Chinese implements Person , InitializingBean , ApplicationContextAware , BeanNameAware { private Axe axe;
private String beanName;
private ApplicationContext ctx; public Chinese() {
super();
System.out.println("1.Spring实例化主调Bean:Chinese实例...");
}
public void setAxe(Axe axe) {
System.out.println("2.Spring调用setAxe执行依赖注入...");
this.axe = axe;
}
public void setBeanName(String name) {
System.out.println("3.===setBeanName===");
this.beanName = name;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("4.===setApplicationContext===");
ctx = applicationContext;
}
public void afterPropertiesSet() throws Exception {
System.out.println("5.正在执行初始化方法afterPropertiesSet()...");
}
public void init(){
System.out.println("6.正在执行初始化方法init...");
}
public void useAxe() {
System.out.println("7." + axe.chop());
} public Axe getAxe() {
return axe;
} public ApplicationContext getCtx() {
return ctx;
} public void setCtx(ApplicationContext ctx) {
this.ctx = ctx;
} public String getBeanName() {
return beanName;
} }

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="chinese" class="edu.pri.lime._7_9_1.bean.impl.Chinese" init-method="init">
<property name="axe">
<bean class="edu.pri.lime._7_9_1.bean.impl.SteelAxe"/>
</property>
</bean> </beans>

        Class : SpringTest

package edu.pri.lime._7_9_1.bean.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_9_1.bean.Person;
import edu.pri.lime._7_9_1.bean.impl.Chinese; public class SpringTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_9_1.xml");
Person person = ctx.getBean("chinese",Chinese.class);
person.useAxe();
}
}

    Console :

1.Spring实例化主调Bean:Chinese实例...
2.Spring调用setAxe执行依赖注入...
3.===setBeanName===
4.===setApplicationContext===
5.正在执行初始化方法afterPropertiesSet()...
6.正在执行初始化方法init...
7.用钢斧砍材真快

      7.9.2 Bean销毁之前的行为

        Spring提供两种方式定制Bean实例销毁之前的特定行为,这两种方式如下:

        ⊙ 实现DisposableBean 接口(优于destory-method属性指定的销毁方法执行)(void destory() throws Exception;)

        ⊙ 使用destory-method属性

        Class : Chinese

package edu.pri.lime._7_9_2.bean.impl;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import edu.pri.lime._7_9_2.bean.Axe;
import edu.pri.lime._7_9_2.bean.Person; public class Chinese implements Person , DisposableBean , BeanNameAware , ApplicationContextAware{ private Axe axe;
private String BeanNane;
private ApplicationContext ctx; public Chinese() {
super();
System.out.println("1.Spring实例化主调Bean:Chinse实例...");
}
public void setAxe(Axe axe) {
System.out.println("2.Spring执行依赖关系的注入...");
this.axe = axe;
}
public void setBeanNane(String beanNane) {
BeanNane = beanNane;
System.out.println("为什么不是我?");
}
public void setBeanName(String name) {
System.out.println("3.调用setBeanName方法...");
this.BeanNane = name;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("4.调用setApplicationContest方法...");
this.ctx = applicationContext; }
public void useAxe() {
System.out.println("5." + axe.chop());
}
public void destroy() throws Exception {
System.out.println("6.正在指定销毁质地去年的方法destory...");
}
public void close(){
System.out.println("7.正在执行销毁之前的方法close...");
}
public ApplicationContext getCtx() {
return ctx;
}
public void setCtx(ApplicationContext ctx) {
this.ctx = ctx;
}
public String getBeanNane() {
return BeanNane;
}
public Axe getAxe() {
return axe;
}
}

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="chinese" class="edu.pri.lime._7_9_2.bean.impl.Chinese" destroy-method="close">
<property name="axe">
<bean class="edu.pri.lime._7_9_2.bean.SteelAxe"/>
</property>
</bean> </beans>

        Class : SpringTest

package edu.pri.lime._7_9_2.bean.main;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_9_2.bean.Person;
import edu.pri.lime._7_9_2.bean.impl.Chinese; public class SpringTest { public static void main(String[] args){
// AbstractApplicationContext 与 ApplicationContext 是什么亲戚?
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_9_2.xml");
Person person = ctx.getBean("chinese",Chinese.class);
person.useAxe();
// 为Spring容器注册关闭钩子,为毛在AbstractApplicationContext中?
ctx.registerShutdownHook();
}
}

        Console :

1.Spring实例化主调Bean:Chinse实例...
2.Spring执行依赖关系的注入...
3.调用setBeanName方法...
4.调用setApplicationContest方法...
5.用钢斧砍材真快
6.正在指定销毁质地去年的方法destory...
7.正在执行销毁之前的方法close...

      7.9.3 协调作用域不同步的Bean

        当Spring容器初始化时,容器会预初始化容器中所有singleton Bean,由于singleton Bean依赖于prototype Bean,因此Spring在初始化singleton Bean之前,会先创建prototype Bean,然后才创建singleton Bean,接下来将prototype Bean注入singleton Bean。一旦singleton Bean初始化完成,它就持有了一个prototype Bean,容器在也不会为singleton Ben执行注入了。

        如果客户端通过该singleton Bean 去掉用prototype Bean的方法时,始终都是调用同一个prototype Bean 实例,这就违背了设置prototype Bean 的初衷,本来希望它具有prototype行为,但实际实际上它却表现出singleton行为。

        当singleton 作用域的Bean依赖于prototype 作用域的Bean时,会产生不同步的现象。

        解决该问题有两种思路:

        ⊙ 放弃依赖注入:singleton作用域的Bean每次需要prototype作用域的Bean时,主动向容器请求新的Bean实例,即可保证每次注入的prototype Bean实例都是最新的实例。

        ⊙ 利用方法注入,通常使用lookup方法注入。

        使用lookup方法注入可以让Spring容器重写容器中Bean的抽象或具体方法,返回查找容器中其他Bean的结果,被查找的Bean通常是一个non-singleton Bean(尽管也可以是一个singleton的)。Spring通过使用JDK动态代理或cglib库修改客户端的二进制码,从而实现上述要求。

        使用lookup方法注入,大致需要如下两步:

        ① 将调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean。

        ② 在<bean.../>元素中添加<lookup-method.../>子元素让Spring为调用者Bean的实现类实现指定的抽象方法。

        在配置文件中为<bean.../>元素添加<lookup-method.../>子元素,<lookup-method.../>子元素告诉Spring需要实现那个抽象方法。Spring为抽象方法提供实现体之后,这个方法就会变成具体方法,这个类也就变成了具体类,接下来Spring就可以创建该Bean的实例了。

        使用<lookup-method.../>元素需要指定如下两个属性:

        ⊙ name : 指定需要让Spring实现的方法;

        ⊙ bean : 指定Spring实现该方法的返回值;

        Spring会采用运行时动态增强的方式来实现<lookup-method.../>元素所指定的抽象方法,如果目标抽象类实现过接口,Spring会采用JDK动态代理来实现该抽象类,并为之实现抽象方法;如果目标抽象类没有实现过接口,Spring会采用cglib实现该抽象类,并为之实现抽象方法。

        Class : Husky

package edu.pri.lime._7_9_3.bean;

public class Husky implements Dog {

    private String name;
public String run() {
return name + "跑丢了";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} }

        Class : Chinese

package edu.pri.lime._7_9_3.bean.impl;

import edu.pri.lime._7_9_3.bean.Dog;
import edu.pri.lime._7_9_3.bean.Person; //1.将调用者Bean的实现类定义为抽象类
public abstract class Chinese implements Person{ private Dog dog;
// 2.定义抽象方法,用于获取被依赖的Bean
public abstract Dog getDog();
public void hunt(){
System.out.println("我带着:" + getDog() + "出去打猎");
System.out.println(getDog().run());
}
public void setDog(Dog dog) {
this.dog = dog;
}
}

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="chinese" class="edu.pri.lime._7_9_3.bean.impl.Chinese">
<!--3. Spring 只要检测到lookup-method元素,Spring会自动为该元素的name属性所制定的方法提供实现体 -->
<!-- name:指定需要让Spring实现的方法; -->
<!-- bean:指定SPring实现该方法的返回值 -->
<lookup-method name="getDog" bean="husky"/>
</bean> <!-- 指定husky Bean的作用域为prototype,希望程序每次使用该Bean时用到的总是不同的实例 -->
<bean id="husky" class="edu.pri.lime._7_9_3.bean.Husky" scope="prototype">
<property name="name" value="哈士奇"/>
</bean> </beans>

        Class : SpringTest

package edu.pri.lime._7_9_3.bean.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_9_3.bean.Person;
import edu.pri.lime._7_9_3.bean.impl.Chinese; public class SpringTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_9_3.xml");
Person perA = ctx.getBean("chinese",Chinese.class);
Person perB = ctx.getBean("chinese",Chinese.class);
System.out.println(perA == perB);
perA.hunt();
perB.hunt();
}
}

        Console :

true
我带着:edu.pri.lime._7_9_3.bean.Husky@574b560f出去打猎
哈士奇跑丢了
我带着:edu.pri.lime._7_9_3.bean.Husky@ba54932出去打猎
哈士奇跑丢了

啦啦啦

7 -- Spring的基本用法 -- 9...容器中Bean的生命周期的更多相关文章

  1. Spring(十二):IOC容器中Bean的生命周期方法

    IOC容器中Bean的生命周期方法 1)Spring IOC容器可以管理Bean的声明周期,Spring允许在Bean生命周期的特定点执行定制的任务. 2)Spring IOC容器对Bean的生命周期 ...

  2. Spring 容器中 Bean 的生命周期

    Spring 容器中 Bean 的生命周期 1. init-method 和 destory-method 方法 Spring 初始化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 s ...

  3. spring IOC 容器中 Bean 的生命周期

    IOC 容器中 Bean 的生命周期: 1.通过构造器或工厂方法创建 Bean 实例 2.为 Bean 的属性设置值和对其他 Bean 的引用 3.调用 Bean 后置处理器接口(BeanPostPr ...

  4. Spring IOC容器中Bean的生命周期

    1.IOC容器中Bean的生命周期 构造器函数 设置属性 初始化函数(在Bean配置中 init-method) 使用Bean 结束时关闭容器(在Bean中配置destroy-method) 2.Be ...

  5. (spring-第1回【IoC基础篇】)Spring容器中Bean的生命周期

    日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期. 人类大脑对图像的认知能力永远高于文字,因此 ...

  6. Spring容器中bean的生命周期以及关注spring bean对象的后置处理器:BeanPostProcessor(一个接口)

    Spring IOC 容器对 Bean 的生命周期进行管理的过程: 1.通过构造器或工厂方法创建 Bean 实例 2.为 Bean 的属性设置值和对其他 Bean 的引用 3.将 Bean 实例传递给 ...

  7. Spring学习-- IOC 容器中 bean 的生命周期

    Spring IOC 容器可以管理 bean 的生命周期 , Spring 允许在 bean 声明周期的特定点执行定制的任务. Spring IOC 容器对 bean 的生命周期进行管理的过程: 通过 ...

  8. IoC基础篇(一)--- Spring容器中Bean的生命周期

    日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回.从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期. 人类大脑对图像的认知能力永远高于文字,因此 ...

  9. IOC容器中bean的生命周期

    一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...

随机推荐

  1. linq操作符:分组操作符

    分组是根据一个特定的值将序列中的元素进行分组.LINQ只包含一个分组操作符:GroupBy.GroupBy操作符类似于T-SQL语言中的Group By语句.来看看GroupBy的方法定义: publ ...

  2. window10删除导航栏中的onedrive

    前面介绍了如何删除导航栏中的“快速访问”,对于一个根本用不着的“oneDrive”肯定也得搞掉. 0.处理前: 1.卸载onedrive是不能清除导航栏里面的onedrive的,进入注册表regedi ...

  3. MFC函数—— CWnd::PreCreateWindow

     CWnd::PreCreateWindow virtual BOOL PreCreateWindow( CREATESTRUCT& cs ); 返回值: 如果要继续窗口的创建过程,则返回非零 ...

  4. orcale存储过程学习之路--存储过程实例(三)

    --创建表 create table TESTTABLE(  id1  VARCHAR2(12),  name VARCHAR2(32))select t.id1,t.name from TESTTA ...

  5. 百度Ueditor设置图片自动压缩

    使用百度Ueditor插入图片的时候,如果图片大于你的编辑框宽度,下面会出现滚动条,如下图: 我们如何设置它的最大宽度为100%呢? 找到ueditor\ueditor.config.js,修改它的i ...

  6. Python __str__函数

    class Cat: def __init__(self,_name): self.name = _name def __str__(self): return "i am %s" ...

  7. linux系统Qt实现简单的任务管理器

    继续上次的操作系统课设,这次需要设计一个简单的任务管理器,大部分人选择GTK来实现,我剑走偏锋,使用Qt来完成这个任务. 用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数.由于 ...

  8. Android 中自定义控件和属性(attr.xml,declare-styleable,TypedArray)的方法和使用

    一. 在res/values 文件下定义一个attrs.xml 文件.代码如下: <?xml version="1.0" encoding="utf-8" ...

  9. go ftp通信

    main.go package main import ( "strings" ftp4go "github.com/shenshouer/ftp4go" &q ...

  10. (笔记)Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...