目录
IOC模块
BeanFactory、applicationContext的容器区别
Bean加载流程、各个接口的应用场景
Spring如何处理循环依赖
spring事件机制?
AOP模块
对spring aop的认识?aop实际应用场景
spring如何支持可扩展的?
spring事物的实现原理
先从BeanFactory和applicationContext的源码,来大致看下这两个类
BeanFactory定义的是一个接口,具体的实现交给子类完成(DefaultListableBeanFactory成熟bean工厂等),定义了些对bean最基本的操作, 主要是获取bean、判断IOC容器中是否存在该bean、判断bean是单例还是多例模式、bean的class类型匹配等,所以通常认为beanFactory是IOC的低级容器。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}
applicationContext接口在定义时,继承了EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver接口,接下来逐一分析
一、ListableBeanFactory、HierarchicalBeanFactory:作为Beanfactory的子类扩展了一些接口,通过继承该接口,可以知道application的具体实现是具备对bean的基本操作的。
二、EnvironmentCapable:表示当前应用程序运行环境的接口。 为应用程序环境的两个关键方面建模:配置文件和属性
三、MessageSource:用于解析消息的策略接口,支持此类消息的参数化和国际化。
四、ApplicationEventPublisher:定义了事件发布的接口
五、ResourcePatternResolver:支持多资源加载。
六、bean的一系统aware实现在加载bean时执行并放入IOC容器中,IOC管理着bean的生命周期
由此可见applicationContext作为高级容器,确实比beanFactory提供的功能强大很多,所以通常在程序是使用applicationContext。
Bean的加载流程:
根据上图,在源码中一一校验,首先看下IOC容器启动时:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 创建ClassPathXmlApplicationContext 加载进行加载bean时,会走调用该方法,可以看到后续refresh(),该方法是创建IOC容器的关键
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
public void refresh() throws BeansException, IllegalStateException {
// 对startupShutdownMonitor加锁,startupShutdownMonitor是有着
// 刷新、创建的同步监视器作用的Object对象,本身并无其他作用
synchronized (this.startupShutdownMonitor) {
// 为refresh做准备工作,如:容器重置为活跃状态,通过ConfigurableEnvironment
// 替换Servlet相关的属性源,验证setRequiredProperties指定的每个属性
// 是否存在并解析为非null值、重置applicationEvent的集合等。
prepareRefresh();
// 刷新bean工厂,首先会通过refreshBeanFactory(),关闭之前的bean工厂,
// 并初始化一个新的bean工厂(关闭bean工厂的同时,会先销毁之前的beans,
// 通过查询源码可以看到在DefaultSingletonBeanRegistry的destroyBean()中
// 调用bean.destroy(),由此也可以看出,当容器进行销毁bean时,若bean实现了
// DisposableBean接口destroy()方法,会在销毁前执行bean具体实现)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理(主要是添加
// ServletContextAwareProcessor的后置处理器,并为beanFactory注册从
// ConfigurableEnvironment中得到的某些bean,比如:servletContext、
// servletConfig、contextParameters、contextAttributes)
postProcessBeanFactory(beanFactory);
// 调用BeanFactory的PostProcessors,这些处理器是在bean定义中向容器注册的(
// 第一步:加载实现了PriorityOrdered接口的PostProcessors
// 第二步:加载实现了Ordered接口的PostProcessors
// 通用的PostProcessors通常都是有顺序的所以根据这两个接口设置的order来决定执行顺序
// 第三步:调用实现Ordered的BeanDefinitionRegistryPostProcessors(bean自行实现的)
// 第四步:调用所有其他的BeanDefinitionRegistryPostProcessors,直到没有其他的出现
// 最后:调用到目前为止所处理的所有处理器的postProcessBeanFactory回调)
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean的processors,在bean创建的过程中被调用(步骤和上个方法相似,最后会将processors注册到IOC容器中)
registerBeanPostProcessors(beanFactory);
// 对消息源进行初始化
initMessageSource();
// 初始化context的事件机制
initApplicationEventMulticaster();
// 初始化其他的特殊bean
onRefresh();
// 检查监听bean,并注册到IOC容器(将监听bean设置initApplicationEventMulticaster()初始化的事件机制中)
registerListeners();
// 实例化所有的(non-lazy-init)单件(非懒加载的单例bean)
// DefaultListableBeanFactory的preInstantiateSingletons()中,
//if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())可见启动时,会先加载 非懒加载单例bean。
finishBeanFactoryInitialization(beanFactory);
// 初始化 LifecycleProcessor、刷新LifecycleProcessor、发送发布通知等。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁之前的beans,通过查询源码可以看到在DefaultSingletonBeanRegistry的destroyBean()中
// 调用bean.destroy(),容器销毁时,销毁bean时,回调bean实现的destroy()方法
destroyBeans();
// 容器活跃状态改为false
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// 清空spring中常见缓存(如:反射中缓存的方法和属性、classLoader类加载器等)
resetCommonCaches();
}
}
}
通过上述源码,可以看到容器关闭时,会调用 bean.destroy(),对bean的销毁最终会调用DisposableBeanAdapter的destory()方法,会判断是否是DisposableBean的实例,然后调用bean重写的destroy()方法,最终通过反射,调用destroyMethod()完成对对象的销毁。
接下来看创建bean的流程,创建bean,是当第一次用到bean时,向IOC容器去getBean(),由于源码太长,故画出流程图,可根据流程图查询源码:
通过对源码的查看,可以验证出之前的加载bean的流程是正确的。
应用场景:aware接口,:像 ApplicationContextAware可以将IOC容器赋值到某个类的属性中。BeanPostProcessor的实现类,可以对某一类bean完成一定的增强效果(例:记录方法的执行时间,若超过指定秒数,输出告警日志)、或初始化资源、又或者进行项目初始化的数据缓存。
具体示例:
定义AsyncSpecifiedBeanPostProcessor接口,后置处理器进行中间件预热
@Bean
public AsyncSpecifiedBeanPostProcessor redisPostProcessorConfigurer(){
return new AsyncSpecifiedBeanPostProcessor() {
@Override
public Class getBeanType() {
return RedisTemplate.class;
}
@Override
public void postProcessAfterInitialization(RedisTemplate redisTemplate, String beanName) {
//调用redis初始化,由于第一次redis调用会比较慢(尤其是其中Cat监控会给redisTemplate加上proxy,由于第一次生成proxy类比较慢,大约需要500ms,刚启动时如果有大量redis调用,都需要500多ms),所以需要调用预热一次,加速启动完成后的访问速度
try {
redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
Jedis jedis = (Jedis) connection.getNativeConnection();
return jedis.get("justForInitTest");
}
});
}catch(Exception e){
if(redisTemplate.getConnectionFactory() instanceof JedisConnectionFactory) {
JedisConnectionFactory cf = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
logger.error("Init redisTemplate(beanName:{}) failed, currentHost:{}, port:{}", beanName, cf.getHostName(), cf.getPort(), e);
}else{
throw e;
}
}
}
};
}
@Component
public class CacheBeanPostProcessor implements BeanPostProcessor, Ordered {
@Override
public int getOrder() {
return 0;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof CacheInterface) {
// 实现该接口的具体实例来完成加载缓存
((CacheInterface) bean).loadCache();
}
return bean;
}
}
【源码解析】Spring如何处理循环依赖?_旺仔的博客-CSDN博客
aop是通过动态代理来实现的,spring管理的bean是通过jdk动态代理、或者cglib动态代理生成的代理对象,而定义好切面类,就可以在代理对象调用目标方法的前后来增加方法。
在《Spring核心原理》中,从ProxyFactoryBean的getObject(),来分析整个aop的原理,可以参考,不过在实际的启动运行流程中,是通过获取bean时调用的initializeBean()方法,可见下图
createAopProxy()会根据 targetClass是接口、动态代理类,通过JDK生成代理类,否则使用JDK生成。两种动态代理的方式分别在JdkDynamicAopProxy的invoke方法、CglibAopProxy的intercept方法,两种方式都是会将解析出来的advice根据目标类、方法来matches出目标方法的所有advice(List
)并根据适配器模式匹配出具体是哪个类型的advice,然后构造出ReflectiveMethodInvocation()对象去执行proceed(),这个方法会循环advice,进行动态匹配判断,执行目标advice,根据advice是前置、后置、异常,来执行代码顺序。如下:
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
// 执行前置方法后,再执行方法调用
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
后置、异常通知类似,可参看AfterReturningAdviceAdapter、ThrowsAdviceAdapter源码。关于bean的切面是如何添加到advised中,经过查阅资料和debug源码,发现在创建bean的前置postproccess中,在遍历调用前置处理器时,SmartInstantiationAwareBeanPostProcessor的AbstractAutoProxyCreator实现了对创建的切面类记录。
aop的应用场景:像spring通过@Transaction自动开启关闭事务、通过@Async来异步执行方法,都是对aop的应用,
一、因此自定义注解是一种场景,在项目中可以通过自定义注解,然后增加自定义注解的切面类,就可以对使用该注解的方法进行增强
二、通过定义切面类,将某个包下的某些命名的类或类的方法进行增强