spring相关文章链接
Bean的生命周期
生产–使用–销毁
生产
loadBeanDefinitions加载bean定义。用xml,注解扫描等方式找到bean的定义放到beanDefinitionMap中
遍历集合beanDefinitionMap,通过createBean创建Bean对象
构造对象,填充属性,初始化实例,注册销毁
1-构造对象
createBeanInstance方法,利用反射机制,从‘bean定义’中的BeanClass拿到这个类的构造方法,规则:只有一个就拿那个,有多个时优先拿@AutoWired注解的构造方法,无注解的拿无参构造,否则报错。对于有参构造,准备参数,在bean的单例池中,根据class找,如果有多个实例,则根据参数名进行匹配
2-填充属性
通过populateBean方法为Bean内部所需的属性值进行赋值填充,通常为@AutoWired注解的变量,通过三级缓存机制进行注入
3-初始化实例
initializeBean初始化Bean对象
初始化容器相关的信息,通过invokeAwareMethods方法,为实现了各种Aware接口的Bean设置诸如BeanName,beanFactory等容器信息
通过invokeInitMethods方法执行Bean的初始化方法,用户通过实现initializingBean的接口而实现的afterPropertiesSet方法
继续会执行initMethod
在执行初始化方法之前及之后,需要对bean后置处理器BeanPostProcessors进行处理,通过applyBeanPostProcessorBeforeInitialization以及applyBeanPostProcessorAfterInitialization分别初始化之前和之后的各种Bean的后置处理,包括负责aop处理的AnnotationAwareAspectJAotoproxyCreator,负责构造后@PostConstruct和销毁前@PreDestory处理的InitDestotyAnnotationBeanPostProcessor等,以及用户通过实现BeanPostProcessor接口的自定义处理器
用户通过实现BeanPostProcessor接口自定义处理器
4–注册销毁
通过注册销毁registerDisposableBean方法,将实现了销毁接口DisposableBean的Bean进行注册,这样在销毁时就可以执行destory方法了
通过以上4步,bean创建好了,用addSingleton方法将bean放入单例池singletonObjects中就可以获取和使用了
使用
销毁
在销毁前要执行“销毁前处理器”PostProcessBeforeDestruction,这里就会执行bean中的@preDestory注解的方法,然后通过destoryBeans方法逐一销毁所在的bean
run之后会经历4个阶段
1.服务构建
2.环境准备
3.容器创建
4.填充容器
上下文初始化中:容器ID,警告日志处理,日志监听 都在这里创建
一.基础知识
1.spring 是什么?
容器,有良好的生态,IOC,AOP
2.IOC
IOC:控制反转,把对象的创建,赋值,管理工作都交给代码之外的容器实现
IOC的技术实现
DI:依赖注入,只需要在程序中提供要使用的对象的名称就可以,至于对象如何在容器中创建,赋值,查找都由容器内部实现。
spring使用的di实现了IOC的功能,spring底层创建对象,使用的是反射机制。
spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。
DI的实现有两种:
1.在spring的配置文件中,使用标签和属性完成,叫做基于XML的DI实现
2.使用spring中的注解,完成属性赋值,叫做基于注解的DI实现
DI的语法分类:
1.set注入(设置注入):spring要调用类的set方法,在set方法可以实现属性的赋值。
2.构造注入,spring调用类的有参数构造方法,创建对象。在构造方法中完成赋值。
基于注解的DI
概念:通过注解完成Java对象创建,属性赋值
使用注解的步骤:
1.加入maven依赖 spring-context,在加入spring-context的同时,间接加入spring-aop依赖。
使用注解必须使用spring-aop依赖
2.在类中加入spring的注解(多个不同功能的注解)
3.在spring的配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置
Bean的定义有xml和注解两种方式
3.bean
通过BeanDefinitionReader读取信息,生成BeanDefinition,也就是bean的定义信息,然后根据这些信息,利用反射生成bean对象
PostProcessor
BeanPostProcessor
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor原理
该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。
首先-初始化bean—>检查容器中是否存在BeanPostProcessor,
如果存在就调用postProcessBeforeInitialization方法
—>如果返回null(或者所有的BeanPostProcessor执行完毕)
---->执行bean的初始化方法
---->再次判断容器中是否存在BeanPostProcessor
—>如果存在就调用postProcessAfterInitialization方法
—>如果返回null(或者所有的BeanPostProcessor执行完毕)
—>运行结束
如果一开始容器中就没有 BeanPostProcessor,那么就会直接支持bean的初始化方法
BeanFactoryPostProcessor
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
其子类 BeanDefinitionRegistryPostProcessor
二.常见问题
1.循环依赖
实例化和初始化是分开执行的
(5)在对象对外暴露的时候,如何准确的给出原始对象或代理对象,因为正常点的代理对象的创建实在BeanPostProcessor的后置处理方法中,在解决循环依赖问题的时候还没有执行到那个地方?
所以此时需要lambda表达式了,类似一种回调机制,在确定对外暴露的时候,就唯一性的确定到底是代理对象还是原始对象,这就是为什么不把对象放到二级缓存中,而是通过三级缓存Lambda表达式的表示方式来执行了
三级缓存不能解决的循环依赖问题
谈谈IOC的理解
AOP
refresh
refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//为进行刷新准备此上下文
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂以便在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
// 允许在子类上下文中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
//调用注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册用来拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
initMessageSource();
// 初始化事件派发器Multicaster
initApplicationEventMulticaster();
//初始化指定上下文中的其他bean
onRefresh();
// 检查侦听器bean并注册它们
registerListeners();
// 实例化所有剩余的(非惰性init)singleton。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的singleton以避免挂起资源。
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
//重置Spring核心中的常见内省缓存,因为我们可能再也不需要单例bean的元数据了
resetCommonCaches();
}
}
}
springboot监听流程
什么是 Actuator
Spring Boot Actuator 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP 跟踪等,帮助我们监控和管理Spring Boot 应用。
这个模块是一个采集应用内部信息暴露给外部的模块,上述的功能都可以通过HTTP 和 JMX 访问。
因为暴露内部信息的特性,Actuator 也可以和一些外部的应用监控系统整合(Prometheus, Graphite, DataDog, Influx, Wavefront, New Relic等)。
这些监控系统提供了出色的仪表板,图形,分析和警报,可帮助你通过一个统一友好的界面,监视和管理你的应用程序。
/health 端点
当我们开启health的健康端点时,我们能够查到应用健康信息是一个汇总的信息,访问
http://127.0.0.1:10111/actuator/health时,我们获取到的信息是{“status”:“UP”},status的值还有可能是 DOWN
健康信息包含磁盘空间、redis、DB,启用监控的这个spring boot应用确实是连接了redis和oracle DB,actuator就自动给监控起来了,确实是很方便、很有用。
解决跨域