对Spring IOC、AOP的认识及项目中应用场景

目录

IOC模块

BeanFactory、applicationContext的容器区别

Bean加载流程、各个接口的应用场景

Spring如何处理循环依赖

spring事件机制?

AOP模块

对spring aop的认识?aop实际应用场景

spring如何支持可扩展的?

spring事物的实现原理


IOC模块

BeanFactory、applicationContext的容器区别

先从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加载流程、各个接口的应用场景

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<RedisTemplate>() {

				@Override
				public Class<RedisTemplate> 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如何处理循环依赖

【源码解析】Spring如何处理循环依赖?_旺仔的博客-CSDN博客

spring事件机制?

AOP模块

对spring aop的认识?aop实际应用场景

aop是通过动态代理来实现的,spring管理的bean是通过jdk动态代理、或者cglib动态代理生成的代理对象,而定义好切面类,就可以在代理对象调用目标方法的前后来增加方法。

在《Spring核心原理》中,从ProxyFactoryBean的getObject(),来分析整个aop的原理,可以参考,不过在实际的启动运行流程中,是通过获取bean时调用的initializeBean()方法,可见下图

 createAopProxy()会根据 targetClass是接口、动态代理类,通过JDK生成代理类,否则使用JDK生成。两种动态代理的方式分别在JdkDynamicAopProxy的invoke方法、CglibAopProxy的intercept方法,两种方式都是会将解析出来的advice根据目标类、方法来matches出目标方法的所有advice(List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

)并根据适配器模式匹配出具体是哪个类型的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的应用,

一、因此自定义注解是一种场景,在项目中可以通过自定义注解,然后增加自定义注解的切面类,就可以对使用该注解的方法进行增强

二、通过定义切面类,将某个包下的某些命名的类或类的方法进行增强

spring如何支持可扩展的?

spring事物的实现原理

猜你喜欢

转载自blog.csdn.net/kolbjbe/article/details/120794871