Spring框架的核心是依赖注入、切面;Spring Boot是在Spring框架的基础上为其提供许多默认配置、默认约定(约定优于配置),从而达到减少或减化配置进而可开箱即用、快速上手;Spring Cloud又是在Spring Boot框架的基础上提供了大量的微服务体系内的各种组件(starter),简化了微服务开发实现的成本;但不管是Spring、Spring Boot、Spring Cloud的底层实现都是充分利用了IOC、AOP;有时我们想在所有Bean都成功注册到IOC容器后,并实例化完成后统一做一些初始化的工作,那么就需要捕获Spring IOC容器初始化后的事件点,而这个事件点我结合自己经验及网上分享进行了一次整理汇总,主要是有如下几种方式(先后触发顺序):

  1. ApplicationContextAware.setApplicationContext
  2. Bean 添加了@PostConstruct的方法
  3. InitializingBean.afterPropertiesSet
  4. BeanPostProcessor (postProcessBeforeInitialization、postProcessAfterInitialization)
  5. SmartLifecycle.start
  6. ApplicationListener.onApplicationEvent
  7. ApplicationRunner.run

下面是把如上的触发点都集中实现在一个Bean中看效果,示例代码如下:

package cn.zuowenjun.demo.ioc.service;

import cn.zuowenjun.demo.ioc.mapper.DemoInfoMapper;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext; import javax.annotation.PostConstruct;
import java.util.Date; @Component
public class DemoModesCollection
implements ApplicationContextAware,
ApplicationListener<ContextRefreshedEvent>,
ApplicationRunner,
SmartLifecycle,
InitializingBean,
BeanPostProcessor { private ApplicationContext context; @PostConstruct
public void postConstructMethod(){
System.out.printf("%1$tF %1$tT.%1$tL --->@PostConstruct postConstructMethod:running!%n",new Date());
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class); System.out.println("@PostConstruct >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
} @Override
public void afterPropertiesSet() throws Exception {
System.out.printf("%1$tF %1$tT.%1$tL --->InitializingBean.afterPropertiesSet:running!%n",new Date());
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("afterPropertiesSet >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
} @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.printf("%1$tF %1$tT.%1$tL --->ApplicationContextAware.setApplicationContext:running! ===beansCount:%2$d %n",
new Date(), applicationContext.getBeanDefinitionCount());
this.context=applicationContext;
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("setApplicationContext >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
} @Override
public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext().getParent() == null || event.getApplicationContext() instanceof WebApplicationContext) {
System.out.printf("%1$tF %1$tT.%1$tL --->ApplicationListener.onApplicationEvent:running! ===beansCount:%2$d (beanType:%3$s) %n",
new Date(), event.getApplicationContext().getBeanDefinitionCount(), event.getApplicationContext().getClass().getTypeName()); DemoInfoMapper mapper= event.getApplicationContext().getBean(DemoInfoMapper.class);
System.out.println("onApplicationEvent >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
}
} @Override
public void run(ApplicationArguments args) throws Exception {
System.out.printf("%1$tF %1$tT.%1$tL --->ApplicationRunner.run:running!%n", new Date());
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("run >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
} private boolean isRunning = false; @Override
public void start() { System.out.printf("%1$tF %1$tT.%1$tL --->SmartLifecycle.start:running!%n",new Date()); isRunning=true; DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("start >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
} @Override
public void stop() {
isRunning = false;
} @Override
public boolean isRunning() {
return isRunning;
} @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%1$tF %1$tT.%1$tL --->BeanPostProcessor.postProcessBeforeInitialization:running!%n",new Date());
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("postProcessBeforeInitialization >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%1$tF %1$tT.%1$tL --->BeanPostProcessor.postProcessAfterInitialization:running!%n",new Date());
DemoInfoMapper mapper= context.getBean(DemoInfoMapper.class);
System.out.println("postProcessAfterInitialization >>>context.getBean:" + (mapper==null?"null":AopUtils.getTargetClass(mapper).getName()));
return bean;
}
}

 如上代码,大家可将尝试其加入到一个spring boot项目中,就可以看到运行的效果(执行的顺序) ,比如我这里的输出如下:

2019-11-16 12:25:48.283 --->ApplicationContextAware.setApplicationContext:running! ===beansCount:325
setApplicationContext >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:48.558 --->@PostConstruct postConstructMethod:running!
@PostConstruct >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:48.559 --->InitializingBean.afterPropertiesSet:running!
afterPropertiesSet >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:48.567 --->BeanPostProcessor.postProcessBeforeInitialization:running!
postProcessBeforeInitialization >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:48.567 --->BeanPostProcessor.postProcessAfterInitialization:running!
......有很多的BeanPostProcessor.postProcessBeforeInitialization、BeanPostProcessor.postProcessAfterInitialization(每一个bean初始化前后都会触发,省略)
2019-11-16 12:25:50.045 --->SmartLifecycle.start:running!
start >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:50.053 --->ApplicationListener.onApplicationEvent:running! ===beansCount:325 (beanType:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext)
onApplicationEvent >>>context.getBean:com.sun.proxy.$Proxy84
2019-11-16 12:25:50.080 --->ApplicationRunner.run:running!
run >>>context.getBean:com.sun.proxy.$Proxy84

从输出结果我们可以看出整个的顺序,那么也得出结论最好是在:SmartLifecycle.start、ApplicationListener.onApplicationEvent、ApplicationRunner.run 这三种实现方式中才能真正达到IOC初始后全部完成后触发的事件点的要求。

注:如果需要在控制台直接看到上面的内容,建议调整spring root的log level,避免无效的日志输出影响观看,配置如:

logging.level.root=error

整理在Spring IOC容器初始化后可以处理特定逻辑的多种实现方式的更多相关文章

  1. Spring IoC容器初始化过程学习

    IoC容器是什么?IoC文英全称Inversion of Control,即控制反转,我么可以这么理解IoC容器: 把某些业务对象的的控制权交给一个平台或者框架来同一管理,这个同一管理的平台可以称为I ...

  2. Spring源码分析:Spring IOC容器初始化

    概述: Spring 对于Java 开发来说,以及算得上非常基础并且核心的框架了,在有一定开发经验后,阅读源码能更好的提高我们的编码能力并且让我们对其更加理解.俗话说知己知彼,百战不殆.当你对Spri ...

  3. Spring Ioc 容器初始化过程

    IOC 是如何工作的? 通过 ApplicationContext 创建 Spring 容器,容器读取配置文件 "/beans.xml" 并管理定义的 Bean 实例对象.   通 ...

  4. 03.Spring IoC 容器 - 初始化

    基本概念 Spring IoC 容器的初始化过程在监听器 ContextLoaderListener 类中定义. 具体由该类的的 configureAndRefreshWebApplicationCo ...

  5. 【spring源码分析】IOC容器初始化(一)

    前言:spring主要就是对bean进行管理,因此IOC容器的初始化过程非常重要,搞清楚其原理不管在实际生产或面试过程中都十分的有用.在[spring源码分析]准备工作中已经搭建好spring的环境, ...

  6. 详解Spring IoC容器

    一.Spring IoC容器概述 1.依赖反转(依赖注入):依赖对象的获得被反转了. 如果合作对象的引用或依赖关系的管理由具体对象来完成,会导致代码的高度耦合和可测试性的降低,这对复杂的面向对象系统的 ...

  7. springmvc web.xml配置之 -- SpringMVC IOC容器初始化

    SpringMVC IOC容器初始化 首先强调一下SpringMVC IOC容器初始化有些特别,在SpringMVC中除了生成一个全局的spring Ioc容器外,还会为DispatcherServl ...

  8. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(6):Spring IOC容器学习(概念、作用、Bean生命周期)

    一.IOC控制反转概念 控制反转(IOC)是一种通过描述(在Java中可以是XML或者是注解)并通过第三方去生产或获取特定对象的方式. 主动创建模式,责任在于开发者,而在被动模式下,责任归于Ioc容器 ...

  9. Spring IoC 容器和 bean 对象

    程序的耦合性: 耦合性(Coupling),又叫耦合度,是对模块间关联程度的度量.耦合的强弱取决于模块间接口的复杂性.调用模块的方式以及通过界面传送数据的多少.模块间的耦合度是指模块之间的依赖关系,包 ...

随机推荐

  1. Linbux下的Bash对拍

    下面是\(Linux\)下的\(bash\)对拍程序: #!/bin/bash t=0 //数据组数 while true; do let "t=$t + 1" echox pri ...

  2. 升级 ASP.NET Core 3.0 设置 JSON 返回 PascalCase 格式与 SignalR 问题

    由于一些 JS 组件要求 JSON 格式是 PascalCase 格式,新版本 ASP.NET Core 3.0 中默认移除了 Newtonsoft.Json ,使用了微软自己实现的 System.T ...

  3. Solr的知识点学习

    Solr单机版的安装与使用 1.Solr单机版的安装与使用,简单写了如何进行Solr的安装与使用.那么很多细节性问题,这里进行简单的介绍.我使用的是Solr与Tomcat整合配置. 2.什么是Solr ...

  4. Python - 正则表达式2 - 第二十三天

    Python3 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. ...

  5. 英语_金丝楠是紫楠(phoebeSheareri)的别名

    姚黄魏紫俱凋零--红木家具今古谈(连载七) [上海木业网]楠木品种包括闽楠.细叶楠.红毛山楠.滇楠.白楠.紫楠.乌心楠.桢楠.水楠.香楠等二百余种之多,1997年的木材国家标准中就列入了八种.某些售卖 ...

  6. 软件设计师【软件工程:软件开发模型、XP极限编程十二最佳实践】

    一.软件开发模型 二.XP极限编程十二最佳实践

  7. Hive的数据倾斜

    目录 什么是数据倾斜 Hadoop框架的特性 主要表现 容易数据倾斜的情况 产生数据清洗的原因 业务场景 空值产生的数据倾斜 不同数据类型关联产生数据倾斜 大小表关联查询产生数据倾斜 一.什么是数据倾 ...

  8. 服务器CPU很高,频繁FullGC排查小总结

    可以分为如下步骤: ①通过 top 命令查看 CPU 情况,如果 CPU 比较高,则通过 top -Hp 命令查看当前进程的各个线程运行情况. 找出 CPU 过高的线程之后,将其线程 id 转换为十六 ...

  9. 【微信小程序】开发实战 之 「视图层」WXML & WXSS 全解析

    在<微信小程序开发实战 之 「配置项」与「逻辑层」>中我们详细阐述了小程序开发的程序和页面各配置项与逻辑层的基础知识.下面我们继续解析小程序开发框架中的「视图层」部分.学习完这两篇文章的基 ...

  10. Uniform Buffer

    Uniform Buffer 是一个很有用的缓存,可以将大量的需要传递至多个着色器的矩阵.向量数据等存储在uniform buffer中.这是一个公共的缓存,所以当多个着色器需要传递相同的数据时,可以 ...