当前位置:   article > 正文

Bean的生命周期_mybits bean生命周期

mybits bean生命周期

1、Bean的简介

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。而bean的定义以及bean相互间的依赖关系将通过配置元数据来描述。

Spring中bean对象默认都是单例的,同一个beanname获取的bean对象都单例的。对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框架之后,每个Action都是单例的,那么对于Spring托管的单例Service Bean,Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于JVM,每个JVM内只有一个实例。

2、Bean的实例化过程

img

①Aware接口及相关子接口

Aware接口从字面上翻译过来是感知捕获的含义。单纯的bean(未实现Aware系列接口)是没有知觉的;实现了Aware系列接口的bean可以访问Spring容器。这些Aware系列接口增强了Spring bean的功能,但是也会造成对Spring框架的绑定,增大了与Spring框架的耦合度。(Aware是“意识到的,察觉到的”的意思,实现了Aware系列接口表明:可以意识到、可以察觉到)

接口源码:

public interface Aware{
    
}
  • 1
  • 2
  • 3

可以发现该接口并没有定义任何方法,所以这只是一个标识接口,该接口的子接口如下:

可以发现子接口,都以Aware结尾,那这些子接口有什么作用呢?

image-20220220183139619

先进入子接口一探究竟

public interface ApplicationEventPublisherAware extends Aware {
    void setApplicationEventPublisher(ApplicationEventPublisher var1);
}
  • 1
  • 2
  • 3
public interface MessageSourceAware extends Aware {
    void setMessageSource(MessageSource var1);
}
  • 1
  • 2
  • 3

我们发现每个子接口都定义了set方法。而方法中的形参类别是接口Aware前面的内容,也就是当前Bean需要感知的内容。所以我们需要在Bean中声明相关的成员变量来接收。

②举例说明
/**
 * 实现了
 * 	ApplicationContextAware
 *  BeanClassLoaderAware
 *  BeanFactoryAware
 *  BeanNameAware
 *  接口
 */
public class User implements ApplicationContextAware,BeanClassLoaderAware,BeanFactoryAware,BeanNameAware{

	private int id;
	
	private String name;
	// 保存感知的信息
	private String beanName;
	// 保存感知的信息
	private BeanFactory beanFactory;
	// 保存感知的信息
	private ApplicationContext ac;
	// 保存感知的信息
	private ClassLoader classLoader;
	
	public BeanFactory getBeanFactory() {
		return beanFactory;
	}

	public ApplicationContext getAc() {
		return ac;
	}

	public ClassLoader getClassLoader() {
		return classLoader;
	}

	public User(){
		System.out.println("User 被实例化");
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getBeanName() {
		return beanName;
	}
	
	/**
	 * 自定义的初始化方法
	 */
	public void start(){
		System.out.println("User 中自定义的初始化方法");
	}
	
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", beanName=" + beanName + "]";
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println(">>> setBeanClassLoader");
		this.classLoader = classLoader;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println(">>> setApplicationContext");
		this.ac = applicationContext;
	}

	@Override
	public void setBeanName(String name) {
		System.out.println(">>> setBeanName");
		this.beanName = name;
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println(">>> setBeanFactory");
		this.beanFactory = beanFactory;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

测试类

@Test
public void test1() {
	ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
	User user = ac.getBean(User.class);
	System.out.println("beanFactory:"+user.getBeanFactory());
	System.out.println("beanName:"+user.getBeanName());
	System.out.println("applicationContext:"+user.getAc());
	System.out.println("classLoader:"+user.getClassLoader());
	System.out.println(user);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3、Bean的生命周期

img

①执行过程:
    • Spring对bean进行实例化,默认bean是单例;
    • Spring对bean进行依赖注入;
    • 如果bean实现了BeanNameAware接口,Spring将bean的名称传给setBeanName()方法;
    • 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory实例传进来;
    • 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;
    • 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization()方法将被调用;
    • 如果bean中有方法添加了@PostConstruct注解,那么该方法将被调用;
    • 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet()接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用;
    • 如果在xml文件中通过标签的init-method元素指定了初始化方法,那么该方法将被调用;
    • 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization()接口方法将被调用;
    • 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
    • 如果bean中有方法添加了@PreDestroy注解,那么该方法将被调用;
    • 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用;

有时候,我们并没有实现那些接口,我们可以除去哪些接口,针对Bean的单例和非单例来描述下bean的生命周期。

②单例Bean

当scope=“singleton”,即默认情况下,会在启动容器时(即实例化容器时)时实例化。但我们可以指定Bean节点的lazy-init="true"来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。如下配置:

<bean id="serviceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>
  • 1

如果想对所有的默认返利bean都应用延迟初始化,可以在根节点beans设置default-lazy-init属性为true,如下所示:

<beans default-lazy-init="true">
  • 1

默认情况下,Spring在读取xml文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用init-method属性值中所指定的方法。对象在被销毁的时候,会调用destroy-method属性值中所指定的方法(例如调用Container.destroy()方法的时候)。写一个测试类,代码如下:

public class LifeBean {
	private String name;  
    
    public LifeBean(){  
        System.out.println("LifeBean()构造函数");  
    }  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        System.out.println("setName()");  
        this.name = name;  
    }  

    public void init(){  
        System.out.println("this is init of lifeBean");  
    }  
      
    public void destory(){  
        System.out.println("this is destory of lifeBean " + this);  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

beans.xml配置如下:

<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" 
			init-method="init" destroy-method="destory" lazy-init="true"/>
  • 1
  • 2

测试代码:

public class LifeTest {
	@Test 
	public void test() {
		AbstractApplicationContext container = 
		new ClassPathXmlApplicationContext("life.xml");
		LifeBean life1 = (LifeBean)container.getBean("life");
		System.out.println(life1);
		container.close();
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
③非单例管理的对象

Prototype作用域和singleton刚刚好相反,singleton只会返回同一个对象,Prototype则是返回一个bean对应多个对象实例,Prototype作用域的bean会导致在每次对这个bean请求(将它注入到另一个bean中,或者以程序的方式调用getBean()方法)时都会创建一个新的bean实例,相当于执行newXxxBean()。Prototypes 原型类型,它在我们创建容器时并没有实例化,只会在我们获取bean的时候才会去创建一个对象,而且我们每次创建的对象都不是同一个对象,根据需要,对有状态的bean应该使用Prototype作用域,对无状态的的bean则可以使用singleton作用域。
来看看Prototype作用域的差别,其余代码同上 ,在。beans.xml中把scope改成prototype

<bean id="life_prototype" class="cn.hsd.mybatis.entity.LifeBean" scope="prototype"
          init-method="init" destroy-method="destroy" lazy-init="true"/>
  • 1
  • 2

测试代码:

@Test
public void test3(){
    AbstractApplicationContext container = new ClassPathXmlApplicationContext("beans.xml");
    LifeBean life1 = (LifeBean) container.getBean("life_singleton");
    LifeBean life2 = (LifeBean) container.getBean("life_singleton");
    System.out.println(life1==life2);//true

    LifeBean life3 = (LifeBean)container.getBean("life_prototype");
    LifeBean life4 = (LifeBean)container.getBean("life_prototype");
    System.out.println(life3==life4);//false

    container.close();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

可以发现,对于作用域为prototype的bean,其destroy方法并没有被调用。如果bean的scope设为prototype时,当容器关闭时,destroy方法不会被调用。对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。
ln(life3==life4);//false

container.close();
  • 1

}


可以发现,对于作用域为prototype的bean,其destroy方法并没有被调用。如果bean的scope设为prototype时,当容器关闭时,destroy方法不会被调用。对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。
  • 1
  • 2
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号