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. 【LOJ#3146】[APIO2019]路灯(树套树)

    [LOJ#3146][APIO2019]路灯(树套树) 题面 LOJ 题解 考场上因为\(\text{bridge}\)某个\(\text{subtask}\)没有判\(n=1\)的情况导致我卡了\( ...

  2. Python-绘制3D柱形图

    Python-绘制3D柱形图 本文主要讲解如何使用python绘制三维的柱形图,可以得到图1所示的效果. 图1 源代码如下: import numpy as np import matplotlib. ...

  3. VM1059 bootstrap-table.min.js:7 Uncaught TypeError: Cannot read property 'classes' of undefined

    参考链接:https://blog.csdn.net/liuqianspq/article/details/81868283 1.阳光明媚的下午,我在写CRUD,让数据传到前端的时候,解析的时候报错了 ...

  4. 大话区块链【Blockchain】

    最近这几天区块链又粉墨登场了,新闻媒体也一直在大量报道,宣称可能要在金融界掀起一番浪潮.甚至有人说很久之前中国就出现了区块链的产物——麻将.那么区块链到底是什么,麻将和区块链又有什么关系呢? 笔者这两 ...

  5. C#中全局作用域的常量、字段、属性、方法的定义与使用

    场景 在开发中,经常会有一些全局作用域的常量.字段.属性.方法等. 需要将这些设置为全局作用域保存且其实例唯一. 注: 博客主页: https://blog.csdn.net/badao_liuman ...

  6. 【转载】Visual Studio2017中如何设置解决方案中的某个项目为启动项目

    在C#的应用程序开发过程中,一个完成的解决方案可能包含多个子项目,有时候需要设置某一个子项目为启动项目,在Visual Studio 2017集成开发工具中,设置解决方案中的某个项目为启动项目的操作方 ...

  7. Spring Cloud Eureka详细说明

    之前学习了如何配置Eureka注册中心.消费者等,关于更详细的一些常用的配置在这里说明. 1.注册中心的自我保护模式 在我们调试Eureka的注册中心时,访问注册中心页面,常常会看见以下提示. 该提示 ...

  8. xshell5运行hadoop集群

    ---恢复内容开始--- 1.CentOS主机配置 在配置Hadoop过程中,防火墙必须优先关闭SELinux,否则将影响后续Hadoop配置与使用,命令如下: # 查看 “系统防火墙” 状态命令 s ...

  9. CVE-2019-0708漏洞利用复现

    CVE-2019-0708漏洞利用复现 距离这个漏洞爆出来也有好几个月了,之前一直忙也没来得及写文档,现在重新做一遍. 准备环境: win7靶机 IP地址:172.16.15.118 Kali攻击机 ...

  10. tornado 文件上传

    服务端 def post(self, *args, **kwargs): # content_type # filename # body file_data=self.request.files i ...