在Spring框架中,@PostConstruct注解、init-method属性、以及afterPropertiesSet()方法通常用于初始化Bean的逻辑。它们都提供了在Bean创建和初始化完成后执行的方法,但执行顺序有所不同。

想要知道@PostConstruct、init-method、afterPropertiesSet()的执行顺序,只要搞明白它们各自在什么时候被谁调用就行了。

代码如下:

import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct; public class Foo implements InitializingBean { public void init(){
System.out.println("执行了init生命周期的初始化回调");
} @PostConstruct
public void postConstruct(){
System.out.println("执行了postConstruct生命周期的初始化回调");
} @Override
public void afterPropertiesSet() {
System.out.println("执行了afterPropertiesSet生命周期的初始化回调");
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class InitConfiguration {
@Bean(initMethod = "init")
public Foo getInitMethodBean() {
return new Foo();
}
}

执行启动类,可以看到在控制台中输出:

执行了postConstruct生命周期的初始化回调
执行了afterPropertiesSet生命周期的初始化回调
执行了init生命周期的初始化回调

@PostConstruct是Java EE 5引入的一个注解,它用于标记一个方法,该方法会在依赖注入完成后自动执行。这意味着,一旦Spring容器完成了Bean的实例化和属性赋值,就会调用这个方法。通常,我们会在这个方法中做一些初始化工作,比如启动服务、初始化数据库连接等。

init-method属性是Spring Bean的一个属性,它允许我们指定一个初始化方法。这个方法会在Bean实例化并完成属性注入后自动执行。与@PostConstruct注解不同的是,init-method属性并不依赖于Spring容器,因此可以在没有Spring的环境中运行。

afterPropertiesSet是SpringFramework中的一个初始化方法,它属于 InitializingBean接口的一部分。当bean的所有属性被Spring容器设置之后,这个方法会被自动调用。它允许开发者在bean属性设置完成之后执行一些特定的操作,如数据库连接池的初始化等。这个方法是在执行其他初始化方法之前被调用的。

源码分析:

通过断点调试发现几个初始化方法都定位到AbstractAutowireCapableBeanFactory的initializeBean方法中

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 此处执行的是@PostConstruct注解的方法 InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
// 执行的是afterPropertiesSet和init-method方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
} if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

执行afterPropertiesSet和init-method方法,在invokeInitMethods方法里面,如下:

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 执行afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
} if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 执行自定义的init-method方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

最终的结论是:@PostConstruct > afterPropertiesSet() > initMethod()的顺序

往期面试题:

Java面试题:SimpleDateFormat是线程安全的吗?使用时应该注意什么?

Java面试题:细数ThreadLocal大坑,内存泄露本可避免

Java面试题:请谈谈对ThreadLocal的理解?

Java面试题:为什么HashMap不建议使用对象作为Key?

Java面试题:你知道Spring的IOC吗?那么,它为什么这么重要呢?

Java面试题:@PostConstruct、init-method和afterPropertiesSet执行顺序?的更多相关文章

  1. 浅谈Java语言中try{}catch{}和finally{}的执行顺序问题

    浅谈Java语言中try{}catch{}和finally{}的执行顺序问题 2019-04-06  PM  13:41:46  1. 不管有没有出现异常,finally块中代码都会执行: 2. 当t ...

  2. java基本数据类型,访问控制符,运算符执行顺序

    1.java数据类型 内置数据类型:boolean(1),  byte(8), char(16), short(8), int(32), long(64), float(32), double(64) ...

  3. java中的try-catch-finally中的return的执行顺序

    在这里看到了try catch finally块中含有return语句时程序执行的几种情况,但其实总结的并不全,而且分析的比较含糊.但有一点是可以肯定的,finally块中的内容会先于try中的ret ...

  4. Java中if else条件判断语句的执行顺序

    学习目标: 掌握 if else 条件判断的使用 学习内容: 1.if语法 if(boolean表达式) { 语句体; } if后面的{}表示一个整体-代码块,称之为语句体,当boolean表达式为t ...

  5. JAVA代码中加了Try...Catch的执行顺序

    public static String getString(){ try { //return "a" + 1/0; return "a"; } catch ...

  6. Java静态代码块、构造代码块执行顺序问题

    package com.zxl.staticdemo; public class BlockTest { static { System.out.println("BlockTest静态代码 ...

  7. Python面试题之多个装饰器执行顺序

    疑问 大部分涉及多个装饰器装饰的函数调用顺序时都会说明它们是自上而下的,比如下面这个例子: def decorator_a(func): print 'Get in decorator_a' def ...

  8. java中异常处理finally和return语句的执行顺序

    finally代码块的语句在return之前一定会得到执行 如果try块中有return语句,finally代码块没有return语句,那么try块中的return语句在返回之前会先将要返回的值保存, ...

  9. java有参无参构造器的的执行顺序

    这里拿了用数组构造栈的一段代码说明一下 public class StackArray<E> { private Object[] data = null; private int max ...

  10. java静态代码块,构造方法,初始化块的执行顺序

    代码Parent和Sub进行讲解 public class Parent { private static final String name; public Parent() { System.ou ...

随机推荐

  1. 使用OHOS SDK构建zlib

    参照OHOS IDE和SDK的安装方法配置好开发环境. 从gitee下载源码,当前最新的提交记录ID为04f42ceca40f73e2978b50e93806c2a18c1281fc. 执行如下命令: ...

  2. OpenHarmony Meetup 广州站 OpenHarmony正当时—技术开源

      招募令 OpenHarmony Meetup 广州站 火热招募中,等待激情四射的开发者,线下参与OpenHarmonyMeetup线下交流 展示前沿技术.探讨未来可能.让你了解更多专属OpenHa ...

  3. Makefile 常用命令详解

    在软件开发中,Makefile是一种非常常用的自动化工具.Makefile文件包含了一系列规则,用于编译.打包.测试等操作,可以帮助我们自动化这些操作,提高项目的管理和编译效率.本文将介绍Makefi ...

  4. MogDB/openGauss存储过程的修改

    MogDB/openGauss 存储过程的修改 SQL 中没有提供显式的存储过程修改命令,通常需要通过 REPLACE 关键字来指定使用当前的存储过程替代之前的同名存储过程. 将前文定义的存储过程替换 ...

  5. Openstack之工作流程

    组件 OpenStack的核心部件即包括Nova(用于计算).Keystone(用于身份服务).Neutron(用于网络和地址管理).Cinder(块存储).Swift(对象存储).Glance(镜像 ...

  6. c# 后端与前端时间戳的转换

    C# DateTime与时间戳转换 C# DateTime与时间戳的相互转换,包括JavaScript时间戳和Unix的时间戳. 1. 什么是时间戳 首先要清楚JavaScript与Unix的时间戳的 ...

  7. 力扣1050(MySQL)-合作过至少三次的演员和导演(简单)

    题目: ActorDirector 表: 写一条SQL查询语句获取合作过至少三次的演员和导演的 id 对 (actor_id, director_id) 示例:  建表语句: 1 create tab ...

  8. 第 1 章 Python 爬虫概念与 Web 基础

    第 1 章 Python 爬虫概念与 Web 基础 1.1 爬虫概念 1.1.1 什么是爬虫 爬虫,即网络爬虫,又称网络蜘蛛(Web Spider),是一种按照一定规则,用来自动浏览或抓取万维网数据的 ...

  9. Timing:在线自习室快速搭建

    ​通过超低延迟的音视频通信技术.视频连麦.弱网传输算法,快速搭建自习场景,提升自习效率. 客户简介 ​ 氪细胞主打产品Timing,是国内最早推出,也是规模最大的在线自习室,是新一代的教育与社交融合平 ...

  10. Spring官方RSocket Broker 0.3.0发布: 快速构建你的RSocket架构

    ​简介:Spring官方的RSocket Broker其实开发已经非常久了,我以为会伴随着Spring Cloud 2021.0发布的,但是没有发生.不过Spring RSocket Broker还是 ...