1.spring官方指定了三种初始化回调方法
  1.1、@PostConstruct、@PreDestory
  1.2、实现 InitializingBean DisposableBean 接口
  1.3、设置init-method和destory-method
  三种方式的优先级从高到低
在spring官方文档里面有明确指出
 Multiple lifecycle mechanisms configured for the same bean, with
different initialization methods, are called as follows:
Methods annotated with @PostConstruct
afterPropertiesSet() as defined by the InitializingBean callback interface
A custom configured init() method
Destroy methods are called in the same order:
Methods annotated with @PreDestroy
destroy() as defined by the DisposableBean callback interface
A custom configured destroy() method

2.三种配置初始化bean的方式,调用时机不同,对于注解,是在spring生命周期中第七个bean后置处理器调用的时候,由CommonAnnotationBeanPostProcessor的postProcessBeforeInitialization()方法来处理

而剩下的两种是在 第七个bean后置处理器执行之后的下一行代码中执行的 
 
3.@PostConstruct和@PreDestroy源码 
  3.1、在spring生命周期中,第三个后置处理器方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors;在CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,调用了buildLifecycleMetadata()方法,有一段比较重要的代码: 
  

 do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//如果目标类中的方法,添加了@PostConstruct注解,就添加到currInitMethods
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
//如果目标类的方法,添加了@PreDestory注解,就添加到currDestroyMethod中
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}); initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);

这里,最终会根据initMethods和destroyMethods来初始化一个LifecycleMetadata对象,然后再把new出来的元对象,存到了一个map中 lifecycleMetadataCache 
 
 private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}

  3.2、在spring生命周期的第七个后置处理器方法中,org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
会尝试先从lifecycleMetadataCache中根据class,获取到元对象,然后调用元对象的 invokeInitMethods()方法 
  

 public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (LifecycleElement element : initMethodsToIterate) {
if (debug) {
logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}

这里的element.invoke()就是调用bean中添加了@PostConstruct注解的方法(method.invoke())
@PreDestory注解的原理是一样的,只是调用时机是在调用annotationConfigApplicationContext.close()方法的时候,会调用
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction 
 
4.剩下的两种初始化方法,执行处理逻辑,是在一块代码中 
 

//在调用第七个后置处理器的下一行,是这个代码
  try {
    invokeInitMethods(beanName, wrappedBean, mbd);
  } 
  

 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable { //判断当前bean是否是 InitializingBean接口的实现类,如果是,判断是否实现了 afterPropertiesSet() 方法
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
} //如果是在@Bean中配置了init-method和destroy-method,那执行的是这里的方法
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

  对于在@Bean注解指定init-method方式的,是在将class扫描到beanDefinition的时候,会对@Bean这种方式的bean进行处理
    loadBeanDefinitionsForBeanMethod(beanMethod);在这里会设置bean的initMethod
  spring扫描bean,将class扫描到beanDefinitionMap中有三种方式;
    @ComponentScan注解
    @Import
        importBeanDefinitionRegistrar
        importSelector
    @Bean 
 
 
5.对于销毁方法,还没仔细研究,后面了解之后,再做补充: 
 
  

 public void destroy() {
//这里是处理@PreDestroy注解的销毁方法
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
} if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
//这里是处理 DisposableBean 接口实现类中destroy()销毁方法的逻辑
((DisposableBean) this.bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
} //这是处理@Bean中 destory-method这种方式的销毁方法
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
 

Spring源码学习(六)-spring初始化回调方法源码学习的更多相关文章

  1. Spring学习(六)-----Spring使用@Autowired注解自动装配

    Spring使用@Autowired注解自动装配 在上一篇 Spring学习(三)-----Spring自动装配Beans示例中,它会匹配当前Spring容器任何bean的属性自动装配.在大多数情况下 ...

  2. spring cloud学习(六)Spring Cloud Config

    Spring Cloud Config 参考个人项目 参考个人项目 : (希望大家能给个star~) https://github.com/FunriLy/springcloud-study/tree ...

  3. Hystrix微服务容错处理及回调方法源码分析

    前言 在 SpringCloud 微服务项目中,我们有了 Eureka 做服务的注册中心,进行服务的注册于发现和服务治理.使得我们可以摒弃硬编码式的 ip:端口 + 映射路径 来发送请求.我们有了 F ...

  4. Spring注解驱动开发(六)-----spring容器创建【源码】

    Spring容器的refresh()[创建刷新] 1.prepareRefresh()刷新前的预处理 1).initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法 ...

  5. spring学习 六 spring与mybatis整合

    在mybatis学习中有两种配置文件 :全局配置文件,映射配置文件.mybatis和spring整合,其实就是把mybatis中的全局配置文件的配置内容都变成一个spring容器的一个bean,让sp ...

  6. spring boot 学习(六)spring boot 各版本中使用 log4j2 记录日志

    spring boot 各版本中使用 log4j2 记录日志 前言 Spring Boot中默认日志工具是 logback,只不过我不太喜欢 logback.为了更好支持 spring boot 框架 ...

  7. Spring Cloud 学习 (六) Spring Cloud Config

    在实际开发过程中,每个服务都有大量的配置文件,例如数据库的配置.日志输出级别的配置等,而往往这些配置在不同的环境中也是不一样的.随着服务数量的增加,配置文件的管理也是一件非常复杂的事 在微服务架构中, ...

  8. Spring boot 学习六 spring 继承 mybatis (基于注解)

    MyBatis提供了多个注解如:@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider,这些都是建立动态语言和让MyBatis执 ...

  9. Bean 注解(Annotation)配置(2)- Bean作用域与生命周期回调方法配置

    Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...

随机推荐

  1. 19、State 状态模式

    “人有悲欢离合,月有阴晴圆缺”,包括人在内,很多事物都具有多种状态,而且在不同状态下会具有不同的行为,这些状态在特定条件下还将发生相互转换.就像水,它可以凝固成冰,也可以受热蒸发后变成水蒸汽,水可以流 ...

  2. Vue中v-model指令的常用修饰符

    v-model指令有三个可以选用的修饰符:.lazy..number以及.trim.vue官方对此的描述为: .number-输入字符串转为有效的数字 .lazy-取代input监听change事件 ...

  3. [转]解决The requested resource is not available的方法

    此博文为转载博文,首先感谢原作者 HTTP Status 404(The requested resource is not available)异常主要是路径错误或拼写错误造成的,请按以下步骤逐一排 ...

  4. 强化学习 3—— 使用蒙特卡洛采样法(MC)解决无模型预测与控制问题

    一.问题引入 回顾上篇强化学习 2 -- 用动态规划求解 MDP我们使用策略迭代和价值迭代来求解MDP问题 1.策略迭代过程: 1.评估价值 (Evaluate) \[v_{i}(s) = \sum_ ...

  5. C++游戏(大型PC端枪战游戏)服务器架构

    实习期间深入参与到某大型pc端枪战游戏的后端开发中,此游戏由著名游戏工作室编写,代码可读性极高,自由时间对游戏后台代码进行了深入研究,在满足自身工作需要的同时对游戏后台的架构也有了理解,记录在此,以便 ...

  6. NodeJs path.resolve的使用

    __dirname __dirname 指向运行代码的文件夹 console.info('__dirname', __dirname) // C:\Leslie\Web_learning\Daily- ...

  7. JavaScript Babel说明

    babel插件只是去唤醒 @babel/core中的转换过程 转换模块需要手动安装 npm install @babel/core 转换方式需要安装 @babel/preset-env babel默认 ...

  8. angular中阿里矢量图标使用

    <!DOCTYPE html> <html lang="en" ng-app="app"> <head> <meta ...

  9. [Kong 与 Konga与postgres数据库] 之 Kuberneres 部署

    1.Kong的概述 Kong是一个clould-native.快速的.可扩展的.分布式的微服务抽象层(也称为API网关.API中间件或在某些情况下称为服务网格)框架.Kong作为开源项目在2015年推 ...

  10. linux手动安装python

    前提:你的linux服务器必须有gcc编译器,gcc查看方法:linux命令行>gcc -v 如果返回版本信息证明已经安装, 如果找不到命令,跳到这篇手动安装gcc >>> l ...