Spring 学习笔记---Bean的生命周期

生命周期图解

由于Bean的生命周期经历的阶段比较多,我们将通过一个图形化的方式进行描述。下图描述了BeanFactory中Bean生命周期的完整过程:


Bean 的生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean,这当中经过了许多关键点,每个关键点都涉及特定方法的调用,可以将这些方法大致划分为3类:
    (1)Bean自身的方法:如调用Bean构造函数,实例化Bean,,调用Setter设置Bean的属性值以及通过<bean>的init-method和destroy-method所指定的方法;
    (2)Bean级生命周期接口方法:如BeanNameAware、BeanFactoryAware、InitializationBean和DisposableBean,这些接口方法由Bean类直接实现;
    (3)容器级生命周期接口方法:如上图中的红色部分所示,由InstantiationAwareBeanPostProcessor和BeanPostProcessor这连个接口实现,一般称他们的实现类为”后处理器“。后处理器接口,一般不由Bean本身实现,他们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中,并通过接口反射为Spring容器预先识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理的编写后处理器,让其仅对感兴趣的Bean进行加工处理.

InstantiationAwareBeanPostProcessor其实是BeanPostProcessor接口的子接口,在Spring 1.2中定义,在Spring2.0中为其提供了一个适配器类InstantiationAwareBeanPostProcessorAdapter,一般情况下,可以方便的扩展改适配器覆盖感兴趣的方法以定义实现类。下面我们通过一个具体的实例以更好的理解Bean生命周期的各个步骤.

窥探Bean生命周期的实例

实现各种生命周期控制访问的Car
package com.spring.beanfactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Car implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{
	private String brand;
	private String color;
	private int maxSpeed;
	private BeanFactory beanFactory;
	private String beanName;
	
	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getMaxSpeed() {
		return maxSpeed;
	}

	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}

	public String getBrand() {
		return brand;
	}

	public BeanFactory getBeanFactory() {
		return beanFactory;
	}

	public String getBeanName() {
		return beanName;
	}

	//1、管理Bean生命周期的接口
	public Car(){
		System.out.println("调用Car构造函数");
	}
	
	public void setBrand(String brand) {
		System.out.println("调用setBrand()设置属性");
		this.brand = brand;
	}

   public void introduce(){
	   System.out.println("bradn:"+brand+";color"+color+"; maxSpeed:"+maxSpeed);
   }
   
   //2、BeanFactoryAware接口方法
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("调用BeanFactoryAware.setBeanFactory()");
		this.beanFactory=beanFactory;
	}
     
	//3、BeanNameAware接口方法
	public void setBeanName(String beanName) {
		System.out.println("调用BeanNameAware.setBeanName()");
		this.beanName=beanName;
	}
    
	
	//4 nitializingBean接口方法
	public void afterPropertiesSet() throws Exception {
		System.out.println("调用InitializingBean.afterPropertiesSet()");
	}
    
	// 5  DisposableBean接口方法
	public void destroy() throws Exception {
		System.out.println("调用DisposableBean.destroy()");
	}
	
	// 6  通过<bean>的init-method属性指定的初始化方法
    public void myInit(){
    	System.out.println("调用inti-method所指定的myInit(),将maxSpeed设置为240.");
    	this.maxSpeed=240;
    }
    
    //7  通过<bean>的destory-method属性指定的销毁方法
    public void myDestory(){
    	System.out.println("调用destory-method所指定的myDestory()方法。");
    }
}
InstantiationAwareBeanPostProcessor实现类
package com.spring.beanfactory;

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

@SuppressWarnings("unchecked")
public class MyInstantiationAwareBeanPostProcessor extends
		InstantiationAwareBeanPostProcessorAdapter {
    
	//1 接口方法:实例化bean前进行调用
	public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException {
		//1-1仅对容器中的car-bean进行处理
		   if("car".equals(beanName)){
			  System.out.println("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()"); 
		   }
		   
		return null;
	}
	
	//2 接口方法:在实例化bean后进行调用
	public boolean postProcessAfterInstantiation(Object bean, String beanName )
	throws BeansException{
		   if("car".equals(beanName)){
				  System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()"); 
			   }
		return true;
	}
	
	
	//3接口方法:在设置某个属性时调用
	public  PropertyValues postProcessPropertyValues(
			PropertyValues propertyvalues,
			PropertyDescriptor apropertydescriptor[], Object bean, String beanName)
			throws BeansException{
     //3-1仅对容器中car-bean进行处理,还可以通过post入参进行过滤,
		//仅对car的某个特定属性进行处理
            		if("car".equals(beanName)){
            		  System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues");	
            		}
				return propertyvalues;
			}
}
BeanPostProcessor实现类
package com.spring.beanfactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {


	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		 if(beanName.equals("car")){
			Car car=(Car)bean; 
			if(car.getColor()==null){
				System.out.println("调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.");
				car.setColor("黑色");
			}
		 }
		return bean;
	}
	
	public Object postProcessAfterInitialization(Object bean, String beanName)
	throws BeansException {
		
		 if(beanName.equals("car")){
			 Car car=(Car)bean;
			 if(car.getMaxSpeed()>=200){
				System.out.println("调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200."); 
				car.setMaxSpeed(200);
			 }
		 }
      return bean;
}

}
在Spring配置文件中定义Car的配置信息
<?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" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean  id="car" class="com.spring.beanfactory.Car" init-method="myInit" destroy-method="myDestory"
       p:brand="红旗CA72"
       p:maxSpeed="300"
       scope="singleton"
   />
  
</beans>
下面我们让容器装载配置文件,然后再分别注册上面所提供的两个后处理器:
package com.spring.beanfactory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class BeanLifeCycle {
	
	private static void LifiCycleInBeanFactory(){
		// 1 下面两句装载配置文件,并启动容器
		Resource res=new  ClassPathResource("beans.xml");
		BeanFactory bf=new XmlBeanFactory(res);
		
		// 2 向容器中注册MyBeanPostProcesser处理器
		((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor());
         //3 向容器中注册MyInstantiationAwareBeanPostProcessor后处理器
		((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
		
		
		//4 第一次从容器中获取car,将处罚容器实例化该Bean,这将引发Bean生命周期方法的调用
		Car car1=(Car)bf.getBean("car");
		car1.introduce();
    	car1.setColor("红色");
		
    	// 5第二次从容器中获取car,直接从缓存池中取(因为 scope="singleton")
		Car car2=(Car)bf.getBean("car");
		
		// 6 查看car1和car2是否指向同一引用
		System.out.println("car1==car2"+(car1==car2));
		
		// 7 关闭容器
		((XmlBeanFactory)bf).destroySingletons();
		
	}
	
	public static void main(String[] args) {
		LifiCycleInBeanFactory();
	}

}
运行后,结果如下:
三月 27, 2014 11:16:39 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
调用Car构造函数
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
InstantiationAwareBeanPostProcessor.postProcessPropertyValues
调用setBrand()设置属性
调用BeanNameAware.setBeanName()
调用BeanFactoryAware.setBeanFactory()
调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.
调用InitializingBean.afterPropertiesSet()
调用inti-method所指定的myInit(),将maxSpeed设置为240.
调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.
bradn:红旗CA72;color黑色; maxSpeed:200
car1==car2true
三月 27, 2014 11:16:39 上午 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
信息: Destroying singletons in org.springframework.beans.factory.xml.XmlBeanFactory@1ed7c33: defining beans [car]; root of factory hierarchy
调用DisposableBean.destroy()
调用destory-method所指定的myDestory()方法。
仔细观察输出的信息,将发现它验证了我们前面所介绍的生命周期的过程。在7处,我们通过destroySingletons()方法关闭容器,由于Car实现了销毁接口并指定了销毁方法,所以容器将触发调用这两个方法.

ApplicationContext中Bean的生命周期

    Bean在应用上下文中的生命周期和在BeanFactory中生命周期类似,不同是,如果Bean实现了org.springframework.context.ApplicationContext接口,会增加一个调用该接口的方法setApplicationContext()步骤, 该方法紧接着BeanFactoryAware之后,
此外,如果配置文件中声明了工厂后处理器接口BeanFactoryPostProcessor的实现类,则应用上下文在装载配置文件之后,初始化Bean实例之前将调用这些BeanFactoryPostProcessor对配置信息进行加工处理。

      ApplicationContext和BeanFactory另一个最大的不同之处在于:前者会利用JAVA机制自动识别出配置文件中定义的BeanPostProcessor,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动将他们注册到应用上下文中;而后者需要在代码中通过手工调用addBeanPostProcessor()方法进行注册。这也是为什么在应用开发时,我们普遍使用ApplicationContext而很少使用BeanFactory的原因之一。
     在ApplicationContext中,我们只需要在配置文件中通过<bean>定义工厂后处理器和Bean后处理器,他们就会按预期的方式执行。
     来看一个使用工厂后处理器的实例,假设我们希望对配置文件中car的brand配置属性进行调整,则可以编写一个如下的工厂后处理器:

工厂后处理器器:MyBeanFactoyPostProcessor.java
package com.spring.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;

public class MyBeanFactoyPostProcessor  implements BeanFactoryPostProcessor{
   //1 对car<bean> 的brand属性配置信息进行“偷梁换柱”的加工操作
	public void postProcessBeanFactory(
			ConfigurableListableBeanFactory bf)
			throws BeansException {
		
		    BeanDefinition bd=bf.getBeanDefinition("car");
		    bd.getPropertyValues().addPropertyValue("brand", "奇瑞QQ");
		    System.out.println("调用BeanFactoryPostProcessor.postProcessBeanFactory()!");
	}
}
ApplicationContext在启动时,将首先为配置文件中的每个<bean>生成一个BeanDefinition对象,BeanDefinition是<bean>在Spring容器中的内部表示。当配置文件中所有的<bean>都被解析成Definition时,ApplicationContext将调用工厂后处理器的方法,因此我们有机会通过程序的方式调整bean的配置信息。在这里,我们将car的BeanDefinition进行调整,将brand属性设置为"奇瑞QQ",下面是具体的配置:
beans.xml
<?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" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!-- 1 这个brand属性的值将被工厂后处理器更改掉-->
   <bean  id="car" class="com.spring.beanfactory.Car" init-method="myInit" destroy-method="myDestory"
       p:brand="红旗CA72"
       p:maxSpeed="300"
   />
   
   <!-- 2 Bean后处理器-->
   <bean id="myBeanPostprocessor" class="com.spring.beanfactory.MyBeanPostProcessor"/>
   
   <!-- 3 Bean工厂后处理器 -->
   <bean id="myBeanFactory" class="com.spring.context.MyBeanFactoyPostProcessor"/>
</beans>
2和3处定义的BeanPostProcessor和BeanFactoryPostProcessor会自动被ApplicationContext识别并注册到容器中。3处注册的工厂后处理器将会对1处配置的属性值进行调整。在2处,我们还定义了一个Bean后处理器,它也可以对1处配置的属性进行调整。启动容器并查看car Bean的信息,我们将发现car Bean的brand属性成功被工厂后处理器修改了.
package com.spring.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.beanfactory.Car;
public class Test {
	public static void main(String[] args) {
           
		ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
		Car car =(Car) ctx.getBean("car");
		System.out.println(car.getBrand());
	}
}
输出信息如下:
三月 27, 2014 1:55:54 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17f1841: startup date [Thu Mar 27 13:55:54 CST 2014]; root of context hierarchy
三月 27, 2014 1:55:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
调用BeanFactoryPostProcessor.postProcessBeanFactory()!
三月 27, 2014 1:55:54 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@16fb592: defining beans [car,myBeanPostprocessor,myBeanFactory]; root of factory hierarchy
调用Car构造函数
调用setBrand()设置属性
调用BeanNameAware.setBeanName()
调用BeanFactoryAware.setBeanFactory()
调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.
调用InitializingBean.afterPropertiesSet()
调用inti-method所指定的myInit(),将maxSpeed设置为240.
调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.
奇瑞QQ



  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
注册 elasticsearchRestTemplate Bean 的方法可以通过使用 spring-boot-starter-data-elasticsearch 提供的 ElasticsearchRestTemplateAutoConfiguration 类来完成。以下是一个示例: ```java import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientProperties; import org.springframework.boot.autoconfigure.elasticsearch.RestClientBuilderCustomizer; import org.springframework.boot.autoconfigure.elasticsearch.RestClientProperties; import org.springframework.boot.autoconfigure.elasticsearch.RestClientPropertiesBuilderCustomizer; import org.springframework.boot.autoconfigure.elasticsearch.RestHighLevelClientBuilderFactory; import org.springframework.boot.autoconfigure.elasticsearch.RestHighLevelClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; @Configuration public class ElasticsearchConfig { @Bean public ElasticsearchRestTemplate elasticsearchRestTemplate( RestHighLevelClientFactory clientFactory, RestHighLevelClientBuilderFactory clientBuilderFactory) { return new ElasticsearchRestTemplate(clientFactory, clientBuilderFactory); } @Bean public RestClientBuilderCustomizer restClientBuilderCustomizer(RestClientProperties properties) { return (builder) -> { // 自定义 RestClientBuilder 的配置 // 可以根据需要进行配置,例如设置连接超时时间、认证等 builder.setRequestConfigCallback((requestConfigBuilder) -> { requestConfigBuilder.setConnectTimeout(properties.getConnectionTimeout()); // 其他自定义配置... return requestConfigBuilder; }); }; } @Bean public RestClientPropertiesBuilderCustomizer restClientPropertiesBuilderCustomizer( ElasticsearchRestClientProperties properties) { return (builder) -> { // 自定义 RestClientProperties 的配置 // 可以根据需要进行配置,例如设置连接池大小、连接保持活动时间等 builder.setMaxRetryTimeout(properties.getMaxRetryTimeout()); // 其他自定义配置... }; } } ``` 在上述示例中,我们通过定义一个 `ElasticsearchRestTemplate` 的 bean 来注册 `elasticsearchRestTemplate`。同时,我们也可以通过自定义 `RestClientBuilderCustomizer` 和 `RestClientPropertiesBuilderCustomizer` 来对 RestClient 进行一些自定义配置。 你可以根据实际需求在 `restClientBuilderCustomizer` 和 `restClientPropertiesBuilderCustomizer` 方法中添加适当的配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值