spring框架理解

Spring AOP


描述一下Spring AOP

面向切面编程,可以看作是对OOP(面向对象编程)的一种补充,传统的OOP开发中代码逻辑是自上而下的,在这些自上而下的过程中会产生横切的问题,而这些横切性的问题又与我们业务逻辑关系不大。AOP让你可以使用简单可插拔的配置,在实际逻辑执行之前、之后或周围动态添加横切关注点。这让代码在当下和将来都变得易于维护。spring AOP可以通过注解和XML两种方式实现。

Spring中有哪些不同的通知类型

1、前置通知(Before Advice):在连接点之前执行Advice   @Before

2、返回之后通知(After Retuning Advice):在连接点正常执行结束之后执行Advice   @AfterReturning

3、抛出异常后执行通知(After Throwing  Advice):方法抛出异常退出后执行该通知   @AfterThrowing

4、后置通知(After advice):无论连接点是通过什么方式退出(正常返回或者抛出异常)都会在执行结束时执行该通知   @After

5、环绕通知(Around advice):围绕连接点执行Advice  @Around

SpringAOP增强一个类,是在什么时候完成?

在spring初始化得时候完成增强。

Spring AOP 代理是什么?

代理是使用非常广泛的设计模式。简单来说,代理是一个看起来像另一个对象的对象,但它添加了一些特殊的功能
Spring AOP是基于代理实现的。AOP 代理是一个由 AOP 框架创建的用于在运行时实现切面协议的对象

spring使用了两种代理模式,JDK动态代理cglib代理
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

spring的2种代理模式:https://blog.csdn.net/ctwy291314/article/details/82017408

Spring IOC


Spring bean的生命周期

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化

  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中

  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法

  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入

  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。

  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。

  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用

  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。

  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。

  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用

 

IOC

IOC(Inversion of Control)多翻译为“控制反转”,与之相似的DI(Dependency Injection)依赖注入,属于同一概念的不同角度解释。

解释IOC:如果没IOC,传统的软件开发,如果对象A依赖对象B,那么对象A在初始化或者运行到某一点是,自己必须主动创建B对象或者使用已创建的对象B,对于对象B的控制权,都在对象A手上。如果对象之间的依赖复杂,系统的耦合就会变得很高。将对象创建的控制权依赖“第三方”来完成,从而实现对象之间的解耦合,这个第三方就是IOC容器,IOC大致可理解为:借助“第三方”实现有依赖对象之间的解耦。

spring容器

从概念上讲:Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。

从具象化讲:通过概念的描述有些同学还是一脸懵逼,在我们的项目中哪个东西是Spring容器?在java项目中,我们使用实现了org.springframework.context.ApplicationContext接口的实现类。在web项目中,我们使用spring.xml——Spring的配置文件。

从代码上讲:一个Spring容器就是某个实现了ApplicationContext接口的类的实例。也就是说,从代码层面,Spring容器其实就是一个ApplicationContext(一个实例化对象)。

https://blog.csdn.net/qq_34598667/article/details/83245753

懒加载

对象使用的时候才去创建。节省资源,但是不利于提前发现错误;

正常情况下,bean的加载是容器启动后就开始的,这样如果加载的过程中有错误,可以立马发现。由于一些特定的业务需求,需要某些bean在IoC容器在第一次请求时才创建,可以把这些bean标记为延时加载。

XML的形式通过beans标签的default-lazy-init="true"来控制。例如<bean id="one" class="com.learn.di.One" lazy-init="true"/>

注解方式通过@Lazy

BeanFactory和FactoryBean有什么区别?

共同点都是接口

BeanFactory是一个工厂类,定义了IOC容器的最基本形式,并提供了IOC容器应遵守的最基本接口,也就是Spring IOC所遵守的最底层和最基本的编程规范。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现,

          但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现。

FactoryBean是spring提供的一个工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑,

FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。

它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式

Spring框架中怎么解决bean的循环依赖?(重要)

总结关于循环引用,如何回答面试:
首先spring在单例的情况下是默认支持循环引用的(当然原形也有办法,今天先不讨论);在不做任何配置的情况下,两个bean相互依赖是能初始化成功的;spring源码中在创建bean的时候先创建这个bean的对象,创建对象完成之后通过判断容器对象的allowCircularReferences属性决定是否允许缓存这个临时对象,如果能被缓存成功则通过缓存提前暴露这个临时对象来完成循环依赖;而这个属性默认为true,所以说spring默认支持循环依赖的,但是这个属性spring提供了api让程序员来修改,所以spring也提供了关闭循环引用的功能;再就是spring完成这个临时对象的生命周期的过程中当执行到注入属性或者自动装配的周期时候会通过getSingleton方法去得到需要注入的b对象;而b对象这个时候肯定不存在故而会创建b对象创建b对象成功后继续b对象的生命周期,当执行到b对象的自动注入周期时候会要求注入a对象;调用getSingleton;从map缓存中得到a的临时对象(因为这个时候a在set集合中;这里可以展开讲),而且获取的时候也会判断是否允许循环引用,但是判断的这个值是通过参数传进来的,也就是spring内部调用的,spring源码当中写死了为true,故而如果需要扩展spring、或者对spring二次开发的的时候程序员可以自定义这个值来实现自己的功能;不管放到缓存还是从缓存中取出这个临时都需要判断;而这两次判断spring源码当中都是默认为true;这里也能再次说明spring默认是支持循环引用的;
参考博客:https://blog.csdn.net/java_lyvee/article/details/101793774

Spring MVC

1、  用户发送请求至前端控制器DispatcherServlet。

2、  DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、  处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、  DispatcherServlet调用HandlerAdapter处理器适配器。

5、  HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、  Controller执行完成返回ModelAndView。

7、  HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、  DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、  ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。


Spring源码分析参考博客:https://www.cnblogs.com/CodeBear/p/10336704.html

spring的事务

spring的事务管理

spring的事务管理有两种实现方式

A:声明式的事务管理

B:编程式的事务管理

spring框架的事务管理机制

PROPAGATION_REQUIRED     支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。
PROPAGATION_REQUIRES_NEW     新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
PROPAGATION_SUPPORTS     支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY     支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED     以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER     以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED     
如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

事务的嵌套

PROPAGATION_REQUIRED(spring 默认)
如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。
假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。
PROPAGATION_REQUIRES_NEW
比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。
那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。
他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。
PROPAGATION_SUPPORTS
假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。
PROPAGATION_NESTED
现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢?  ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:
a、捕获异常,执行异常分支逻辑
void methodA() { 
        try { 
            ServiceB.methodB(); 
        } catch (SomeException) { 
            // 执行其他业务, 如 ServiceC.methodC(); 
        } 
    }
这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。
b、 外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback

https://www.cnblogs.com/yaohuiqin/p/9491904.html

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章