Spring Bean的生命周期,总结为五大阶段,十三个环节,如下图所示:
Bean生命周期流程图
每个阶段详解的说明可以参考:Spring Bean生命周期详解
下面是不是开始讲怎么用了?慢着,现在是Springboot的天下,先看一下Springboot中是怎么管理Bean的
先从启动类SpringApplication开始
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
源码就不一一跟了,重点在this.refreshContext(context);接着进入AbstractApplicationContext.refresh()方法
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 准备刷新
this.prepareRefresh();
// 获取BeanFactory;默认实现是DefaultListableBeanFactory,在创建容器的时候创建的
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 设置beanFactory类加载器,添加多个beanPostProcesser
this.prepareBeanFactory(beanFactory);
try {
// BeanFactory准备工作完成后进行的后置处理工作
this.postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor各个实现类的方法
this.invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类
this.registerBeanPostProcessors(beanFactory);
//初始化ApplicationContext的MessageSource(做国际化功能;消息绑定,消息解析);
this.initMessageSource();
//初始化ApplicationContext事件广播器
this.initApplicationEventMulticaster();
// 初始化子类特殊bean(钩子方法,如创建Tomcat,Jetty等WEB服务器)
this.onRefresh();
// 注册事件监听器
this.registerListeners();
// 初始化所有非懒加载的singleton bean
this.finishBeanFactoryInitialization(beanFactory);
// 广播事件(ContextRefreshedEvent),完成context的刷新
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
源码中特意添加了注释,大家可以自己和上面Bean生命周期的节点一一对应。
从理论到实践
这么多内容根本记不住啊,下面我们来划重点,结合项目中的应用来帮助大家记忆,需要记住以下几个关键点:
1、registerBeanDefinition:执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition 就被放入了容器中,后续获取 Bean 也是从这个容器中获取,在插件式开发中经常用到,是加载fatjar的关键。下面是一个在Springboot启动后将jar包中的class注册成bean的例子:
/**
* 将jar包插件中的class注册成bean.
*
* @param classes
*/
private void registBean(Vector<Class> classes) {
BeanDefinitionRegistry beanDefinitionRegistry = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
classes.forEach(c -> {
// 将有Component注解的类注册成bean
Component annotation = AnnotationUtils.findAnnotation(c, Component.class);
if (null != annotation && condition(c)) {
// 如果Component未指定bean名称, 就用第一个字母小写的类名作为bean名称.
String beanName = annotation.value();
if (!StringUtils.hasText(beanName)) {
char[] cs = c.getSimpleName().toCharArray();
cs[0] = ("" + cs[0]).toLowerCase().toCharArray()[0];
beanName = String.valueOf(cs);
}
// 注册bean.
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(c);
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
logger.info("[{}] registered as {}", c.getName(), beanName);
}
});
}
2、InstantiationAwareBeanPostProcessor:作用于实例化阶段的前后,实现了InstantiationAwareBeanPostProcessor接口的bean,是@Autowired、@Value注解的依赖注入的关键。
下面是@Autowired的2处关键源码,可以看出@Autowired是利用了InstantiationAwareBeanPostProcessor和java反射机制实现的
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
// InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
// 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 忽略后续的属性赋值操作代码
}
public void processInjection(Object bean) throws BeanCreationException {
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null);
try {
metadata.inject(bean, (String)null, (PropertyValues)null);
} catch (BeanCreationException var5) {
throw var5;
} catch (Throwable var6) {
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", var6);
}
}
3、BeanPostProcessor:作用于初始化阶段的前后,Spring AOP的实现原理就是从BeanPostProcessor接口postProcessBeforeInitialzation方法开始的。
下面是一段自定义注解的方式发送日志埋点的例子:
/**
* 发送埋点数据
* 调用次数类型指标
*/
@After(value = "@annotation(com.iflytek.cosmo.guidance.annotation.CosmoCriusAnnotation)")
public void doAfter(JoinPoint point) throws Throwable {
logger.debug("CriusAspect doAfter begin");
// 获取方法签名
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
CosmoCriusAnnotation criusAnnotation = targetMethod.getAnnotation(CosmoCriusAnnotation.class);
//获取发送的指标
String metric = criusAnnotation.criusMetric();
CriusMetaData criusMetaData;
try {
if (CriusMetricConstant.WEBSOCKET.equals(criusAnnotation.metricType())) {
Object[] obj = point.getArgs();
WebSocketSession session = (WebSocketSession) obj[0];
//转写开始时间埋点
session.getAttributes().put(CriusMetricConstant.BEGINTIME, System.currentTimeMillis());
//转写字数埋点
session.getAttributes().put(CriusMetricConstant.TRANSLITERATIONWORDS, 0);
criusMetaData = criusService.getCriusMetaDataBySession(session);
} else {
criusMetaData = criusService.getCriusMetaData();
}
//判断appid是自有还是第三方
if (selfAppIdProperties.getSelfAppIds().contains(criusMetaData.getAppId())) {
metric += ".self";
//发送一次自有应用总调用次数
criusService.sendDataToCrius(criusMetaData, CriusMetricConstant.BIZ_NL_SELF, 1);
} else {
metric += ".third";
//发送一次第三方总调用次数
criusService.sendDataToCrius(criusMetaData, CriusMetricConstant.BIZ_NL_THIRD, 1);
}
//发送对应能力的埋点数据
criusService.sendDataToCrius(criusMetaData, metric, 1);
} catch (Exception e) {
logger.error("CriusAspect error:{}", e);
}
}