SpringBoot日常:Spring扩展接口之InitializingBean

2024-08-29 16:20

本文主要是介绍SpringBoot日常:Spring扩展接口之InitializingBean,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 简介
    • 源码分析
    • 应用场景
    • 代码示例
    • 运行示例

简介

这篇文章主要介绍了Spring中InitializingBean的使用详细解析,InitializingBean是Spring提供的拓展性接口,提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

源码分析

我们大概看一下初始化涉及的源码部分,主要为这两个方法,
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean#invokeInitMethods

/*** @return the initialized bean instance (potentially wrapped)* @see BeanNameAware* @see BeanClassLoaderAware* @see BeanFactoryAware* @see #applyBeanPostProcessorsBeforeInitialization* @see #invokeInitMethods* @see #applyBeanPostProcessorsAfterInitialization*/protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//执行BeanPostProcessor接口实现类的postProcessBeforeInitialization方法wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//如果bean实现了InitializingBean或者自定义了initMethod,//会在这里执行InitializingBean#afterPropertiesSet和initMethod方法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()) {//执行BeanPostProcessor接口实现类的postProcessAfterInitialization方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//判断bean是否实现了InitializingBeanboolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("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,真接调用afterPropertiesSet(),((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {//获取bean自定义的init-method方法String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {//如果自定义了init-method方法,在这里开始执行;invokeCustomInitMethod(beanName, bean, mbd);}}}

看完源码部分,我们可以很清楚地知道InitializingBean#afterPropertiesSet方法和init-method是什么时候用什么方式来调用的( 通过反射调用init-method),且InitializingBean#afterPropertiesSet方法的执行时机要稍早于init-method。另外,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法

应用场景

这个扩展点是比较有用的一个扩展点,可以用于

  • 修改默认设置的属性
  • 添加补充额外的属性值
  • 或者针对关键属性做校验
  • spring MVC内容有一个经典的实现场景,RequestMappingHandlerMapping完成URL与controller的映射工作
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {@Overridepublic void afterPropertiesSet() {initHandlerMethods();}	protected void initHandlerMethods() {//循环所有的beanfor (String beanName : getCandidateBeanNames()) {//如果bean名字不是以scopedTarget.开头if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {processCandidateBean(beanName);}}//日志输出handlerMethodsInitialized(getHandlerMethods());}protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}//他们是否是Handler(类上标注@Controller注解或者@RequestMapping注解)if (beanType != null && isHandler(beanType)) {//获取这个类上所有标注@RequestMapping的方法信息,以RequestMappingInfo形式把他们储存到MappingRegistry中detectHandlerMethods(beanName);}}

代码示例

完成一个rsa对象的初始化,方便该类方法调用使用

@Slf4j
@Configuration
public class ExtendInitializingBean implements InitializingBean {private RSA rsa;@Overridepublic void afterPropertiesSet() {String priv = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJzDhvCJBIIuZzNu\n" +"+dHWY5inSAN6d/yqWOTl/5rWofT2+m59qjKoFuJ9kkuYUCkIpoEtLhu5PfOAdR9R\n" +"bsVnfXThgwOQFHx1/v4URXwOBrBHRYhPy8fApJSfdBWgKMs9GZ5WbDWVkPm7xhvJ\n" +"t716Wtx/leCjvq87jWVg8oo83uKtAgMBAAECgYAW77bNInG3QxHUy9kf03XpY8Rc\n" +"xJeiBMyShSJjuyFMMFy45jMM9rIOe8qiu+DdTXI14UXnRtsNHHpGgEmBoYrl4IZ9\n" +"Wgbxn0fkrcHaw4F8GoAapyqAgNkyU3kAf8of6G+ZeMulcZtbb7NXVkwTaRHOkzBg\n" +"2a44HCSQ2n/fHPxfwwJBANFhUKWMOV3SqEN7RjsxWNAk8P25xHzIWq6KCyhOx5Vm\n" +"KLIttnYUiA3UA3q5RJK8Hqh0a2JGcg8O9HawOuMWAAsCQQC/qxNG08pX8dm5mh5B\n" +"9d/Wc09U9V7Xni9gqqS5adjxChm97t5h8k3wRxTqDWHCJyZTkezy7pmZvaFWqwLO\n" +"xkMnAkBLEbIBeNIEkoejkiovBNVL40LIJXeOKaNhmrq/W+dw6CzFHWCi21+gXZhV\n" +"wuEUHwB68yqhFJLGVV1OxIaIbpXbAkBBY0WiRiKjuhiDHzbvXchNSu1nmIYQnSCg\n" +"o9aqgpfGM6HwkAtB8v3v2PAjoQkWyXBj1ka14fx43J6sCI9ep3jFAkBDi3wnlIzc\n" +"LpJxumw84P8f3pVJ1xKx9tchAh1W+hhcaq+/S+u3rIJcXfXWLojUp7yMyKjzy2lU\n" +"PNC8Qke0R/qC";String pub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcw4bwiQSCLmczbvnR1mOYp0gD\n" +"enf8qljk5f+a1qH09vpufaoyqBbifZJLmFApCKaBLS4buT3zgHUfUW7FZ3104YMD\n" +"kBR8df7+FEV8DgawR0WIT8vHwKSUn3QVoCjLPRmeVmw1lZD5u8Ybybe9elrcf5Xg\n" +"o76vO41lYPKKPN7irQIDAQAB";rsa = new RSA(priv, pub);log.info("afterPropertiesSet--Extend--run");}}

运行示例

在这里插入图片描述

这篇关于SpringBoot日常:Spring扩展接口之InitializingBean的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118356

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S