Spring 系列总结

1. Spring IOC & AOP

IOC:(Inverse of Control:控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC容器是Spring用来实现IoC的载体,IoC容器实际上就是个Map(key,value),Map中存放的是各种对象。

将对象之间的相互依赖关系交给IoC容器来管理,并由IoC容器完成出来对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IoC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

AOP:能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务管理、日志管理、权限控制)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

Spring AOP是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象(有些类单类,不去实现接口),就无法使用JDK Proxy去进行代理,这时候Spring AOP会使用Cglib,生成一个被代理对象的子类来作为代理。

1.1 源码阅读

以下通过一些简洁的语言简述了IOC容器创建的过程以及bean的生命周期。

    /**
     *  IOC 容器刷新过程
     * @throws BeansException
     * @throws IllegalStateException
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            /**
             * 第一步:
             *      1. 初始化一些属性。
             *      2. 校验属性的合法性
             *      3. 保存容器刷新的一些早期事件。
             */
            prepareRefresh();

            /**
             * 第二步:
             *      1.创建 beanFactory (通过 CAS 设置创建的属性,CAS 真是无处不在)
             */
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            /**
             * 第三步:
             *      1. 给 beanFactory 添加一些属性和组件
             */
            prepareBeanFactory(beanFactory);

            try {
                /**
                 * 第四步:
                 *      1. 空方法,子类实现该方法进行自定义逻辑
                 */
                postProcessBeanFactory(beanFactory);

                /**
                 * 第五步:
                 *      1. 执行 beanFactory 的后置处理器。主要包括 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor
                 */
                invokeBeanFactoryPostProcessors(beanFactory);

                /**
                 * 第六步:
                 *      1. 注册所有的 BeanPostProcessors 到 beanFactory
                 */
                registerBeanPostProcessors(beanFactory);

                /**
                 * 第七步:
                 *      1. 初始化 MessageSource 组件,主要用于国际化,消息绑定解析等
                 */
                initMessageSource();

                /**
                 * 第八步:
                 *      1. 初始化 ApplicationEventMulticaster 事件多播器,用于事件的广播
                 */
                initApplicationEventMulticaster();

                /**
                 * 第九步:
                 *      1. 空方法,子类可以实现该方法自定义逻辑
                 *      2. 例如 SpringMVC 在该方法初识了八大组件,Tomcat 在该方法创建启动。
                 */
                onRefresh();

                /**
                 * 第十步:
                 *      1. 注册 Listeners 监听器,监听之间多播器的内容
                 */
                registerListeners();

                /**
                 * 第十一步:( bean 的生命周期)
                 *      1. 通过 getBean() 获取类的 BeanDefinition 定义信息。
                 *      2. BeanDefinition 定义信息中存储了对象的各种属性。
                 *      3. 通过 createBean() 方法真正创建对象。
                 *      4. 先调用 Instantiation 前后的 BeanPostProcessor 后置处理器
                 *      5. 如果有实现各种 xxxAware 接口的则设置一些值。
                 *      6. 然后执行初始化方法,初始化前后又有 Initialization 的后置处理器
                 *          (1) AOP 功能就在此处实现:
                 *          (2)通过 AnnotationAwareAspectJAutoProxyCreator 会调用 postProcessAfterInitialization() 方法
                 *          (3)该后置处理器会检查生成的对象是否是需要增强的对象
                 *          (4)如果是,则保存它的所有增强方法,并创建一个代理对象返回
                 *          (5)之后对该对象的获取,其实是获取了它的代理对象
                 *          (6)执行方法时会被拦截器,将该代理对象的所有增强方法包装成一个拦截器链,进行链式调用
                 *      7. 最后给该对象注册销毁方法
                 *      8. 穿件完成之后,将单例对象加入到单例池中
                 */
                finishBeanFactoryInitialization(beanFactory);

                /**
                 * 第十二步:
                 *      1. 完成刷新,清理一些内容。
                 */
                finishRefresh();
            }
            /**
             * 如果捕捉到异常就销毁所有 bean 并取消刷新标记。
             */
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
                destroyBeans();
                cancelRefresh(ex);
                throw ex;
            }
            finally {
                resetCommonCaches();
            }
        }
    }

1.2 解决单例的循环依赖

循环依赖通过三级缓存解决:

  • 第一级:singletonObjects:用于存放完全初始化好的bean,从该缓存中取出的bean可以直接使用。
  • 第二级:earlySingletonObjects:存放原始的bean对象(尚未填充属性),用于解决循环依赖
  • 第三级:singletonFactories:存放bean工厂对象,用于解决循环依赖

例如 :

  1. A 的属性依赖于 B,B 又依赖于 A,所以当 A 创建对象的时候,先进行了第一步操作,获取到了工厂bean,并加入到第三级缓存中,继续初始化的时候发现需要注入 B,则先去创建B。
  2. B 发现自己需要注入 A,则先去获取 A,发现,第一级缓存和第二级缓存都没有,但是可以从第三级缓存中获取,则获取到A,并完成了创建。
  3. 之后 A 也可以获取到 B 完成创建。

2. Spring 事务

2.1 事务传播

事务就是 AOP 的具体应用,会生成开启事务方法的代理对象,在获取该对象操作时,会执行代理对象的方法,先设置事务为非自动提交,然后开启事务,最后提交事务或者回滚事务。

事务的传播级别:

    /**
     * 如果当前存在事务,则加入该事务,不存在则创建一个新的事务
     */
    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

    /**
     * 如果当前存在事务,加入该事务,不存在则以非事务的方式运行
     */
    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

    /**
     * 如果当前存在事务,加入该事务,不存在则抛出异常
     */
    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

    /**
     * 创建一个新的事务,如果当前存在事务则挂起
     */
    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

    /**
     * 非事务方式运行,有事务则挂起
     */
    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

    /**
     * 非事务方式运行,存在事务则抛出异常
     */
    NEVER(TransactionDefinition.PROPAGATION_NEVER),

    /**
     * 如果当前存在事务,则创建⼀个事务,作为当前事务的嵌套事务来运⾏;
     */
    NESTED(TransactionDefinition.PROPAGATION_NESTED);

2.2 SpringBoot 事务实现

首先通过 @EnableTransactionManagement 注解会为容器倒入一个 TransactionManagementConfigurationSelector 的选择器,也就是对事务的自动配置,会为需要事务处理的对象生成代理对象,通过拦截器 TransactionInterceptor 拦截进行调用,主要会进入拦截器的 invoke 方法。

	@Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

很明显可以看出,就是通过 AOP 对于方法进行增强,调用 invokeWithinTransaction 添加事务操作。

    @Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                             final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final TransactionManager tm = determineTransactionManager(txAttr);

        // 省略响应式编程的事务操作

        PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
            // 根据传播级别判断是否需要创建事务
            TransactionAspectSupport.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

            Object retVal;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // 拦截链的放行
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }

            if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
                // Set rollback-only in case of Vavr failure matching our rollback rules...
                TransactionStatus status = txInfo.getTransactionStatus();
                if (status != null && txAttr != null) {
                    retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                }
            }
            // 最后判断是否提交
            commitTransactionAfterReturning(txInfo);
            return retVal;
        } else {
            Object result;
            final TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder();

            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
                    TransactionAspectSupport.TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
                    try {
                        Object retVal = invocation.proceedWithInvocation();
                        if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
                            // Set rollback-only in case of Vavr failure matching our rollback rules...
                            retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
                        }
                        return retVal;
                    }
                    catch (Throwable ex) {
                        if (txAttr.rollbackOn(ex)) {
                            // A RuntimeException: will lead to a rollback.
                            if (ex instanceof RuntimeException) {
                                throw (RuntimeException) ex;
                            }
                            else {
                                throw new TransactionAspectSupport.ThrowableHolderException(ex);
                            }
                        }
                        else {
                            // A normal return value: will lead to a commit.
                            throwableHolder.throwable = ex;
                            return null;
                        }
                    }
                    finally {
                        cleanupTransactionInfo(txInfo);
                    }
                });
            }

            // 省略大量异常的处理

            return result;        

3. 过滤器 (Filter) 和 拦截器 (Interceptor)

过滤器 和 拦截器 均体现了AOP的编程思想。

不同点:

  • 实现原理:
    • 过滤器 是基于函数回调的;
    • 拦截器 则是基于Java的反射机制(动态代理)实现的。
  • 使用范围:
    • 过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
    • 拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。
  • 触发时机不同:
    • 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
    • 拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值