SpringBoot注解---4.扩展原理

一、Bean的生命周期管理

  1. bean的实例化:调用bean的构造方法,我们可以在bean的无参构造方法中执行相应的逻辑。
  2. bean的初始化:在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,在该方法中咱们可以执行自定义的逻辑。
  3. bean的销毁:可以通过@PreDestroy注解、DisposableBean和destroy-method来指定bean在销毁前执行的方法,在该方法中咱们可以执行自定义的逻辑。

1.通过@Bean指定init-method和destroy-method

@Bean(initMethod="init", destroyMethod="destroy")
public Car car() {
    return new Car();
}

使用时机:

  1. 初始化方法:对象创建完成,如果对象中存在一些属性,并且这些属性也都赋好值之后,那么就会调用bean的初始化方法。
  2. 销毁的方法:可以对数据源的连接等信息进行关闭和清理。
  单实例 多实例
初始化 对于单实例bean来说,在Spring容器创建完成后,Spring容器会自动调用bean的初始化方法 在每次获取bean对象的时候,调用bean的初始化方法
销毁 在容器关闭的时候,会调用bean的销毁方法 Spring容器不会管理这个bean,也就不会自动调用这个bean的销毁方法了

2.通过让bean实现InitializingBean和DisposableBean两个接口

(1)初始化bean

Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。

  1. 实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。
  2. 如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。

(2)销毁bean

  1. 实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。
  2. 使用destroy-method

 前者与Spring耦合高,使用类型强转.方法名(),效率高;后者耦合低,使用反射,效率相对来说较低。

【 注意】多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean接口中的方法是由Spring容器来调用的,所以如果一个多实例bean实现了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调用,当然了,在XML配置文件中指定了destroy方法,也是没有任何意义的。所以,在多实例bean情况下,Spring是不会自动调用bean的销毁方法的。

package com.meimeixia.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class Cat implements InitializingBean, DisposableBean {
	
	public Cat() {
		System.out.println("cat constructor...");
	}

	/**
	 * 会在容器关闭的时候进行调用
	 */
	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat destroy...");
	}

	/**
	 * 会在bean创建完成,并且属性都赋好值以后进行调用
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat afterPropertiesSet...");
	}

}

3.使用JSR-250规范里面定义的@PostConstruct和@PreDestroy两个注解

@PostConstruct注解是Java中的注解,并不是Spring提供的注解。@PostConstruct和@PreDestroy是Java规范JSR-250引入的注解,定义了对象的创建和销毁工作,同一期规范中还有@Resource注解,Spring也支持了这些注解。

package com.meimeixia.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Component;

/**
 *
 * @author liayun
 *
 */
@Component
public class Dog {

	public Dog() {
		System.out.println("dog constructor...");
	}
	
	// 在对象创建完成并且属性赋值完成之后调用
	@PostConstruct
	public void init() {
		System.out.println("dog...@PostConstruct...");
	}
	
	// 在容器销毁(移除)对象之前调用
	@PreDestroy
	public void destory() {
		System.out.println("dog...@PreDestroy...");
	}
	
}
 注解 源码 执行顺序
@PostConstruct

在bean创建完成并且属性赋值完成之后,来执行初始化方法。

Constructor(构造方法)→@Autowired(依赖注入)→@PostConstruct(注释的方法)

@PreDestroy

在容器销毁bean之前通知我们进行清理工作。

调用destroy()方法→@PreDestroy→destroy()方法→bean销毁 

4.通过让bean实现BeanPostProcessor接口

(1)BeanPostProcessor是什么?

BeanPostProcessor是一个接口,其中有两个方法,Spring容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接口的实现类中的这两个方法。

 接口 调用时机
postProcessBeforeInitialization 在bean实例化和属性设置之后,自定义初始化方法之前被调用
postProcessAfterInitialization 在自定义初始化方法之后被调用
package com.meimeixia.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 后置处理器,在初始化前后进行处理工作
 * @author liayun
 *
 */
@Component // 将后置处理器加入到容器中,这样的话,Spring就能让它工作了
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
		return bean;
	}

	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return 3;
	}

}

当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义的BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。

(2)作用

  后置处理器可用于bean对象初始化前后进行逻辑增强。Spring提供了BeanPostProcessor接口的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理等等。

(3)原理

在Spring中调用initializeBean()方法之前,还调用了populateBean()方法来为bean的属性赋值

在applyBeanPostProcessorsBeforeInitialization()方法中,会遍历所有BeanPostProcessor对象,然后依次执行所有BeanPostProcessor对象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor对象的postProcessBeforeInitialization()方法返回null以后,则后面的BeanPostProcessor对象便不再执行了,而是直接退出for循环。

populateBean(beanName, mbd, instanceWrapper); // 给bean进行属性赋值
initializeBean(beanName, exposedObject, mbd)
{
	applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd); // 执行自定义初始化
	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

(4)Spring底层对BeanPostProcessor的使用

bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanProcessor等。

原文地址:https://www.cnblogs.com/nxf-rabbit75/p/14619893.html