解析类-》加载对象-》依赖注入-》回调Aware方法-》后置处理器处理(初始化及初始化前后)-》使用-》销毁
-
Bean 容器解析类得到配置文件中 Spring Bean 的定义(BeanDefinition)。(解析)
-
Bean 容器利用 Java Reflection API 创建一个Bean的实例。(加载对象)
-
如果涉及到一些属性值(加了@Autowride注解的属性)利用 set()方法给对象设置属性。(依赖注入)
-
回调Aware方法:如果实现了其他
*.Aware
接口,就调用相应的方法。(回调Aware方法)①如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。
②如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
-
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor对象,执行postProcessBeforeInitialization() 方法。(后置处理器初始化前方法)
-
如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。(初始化方法)
-
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
-
如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。(后置处理器初始化后方法,会进行AOP)
-
当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
-
当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
图示:
后置处理器BeanPostProcessor :在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。后置处理器分为 Bean Factory后置处理器(视线了Spring的扫描)和Bean后置处理器(实现了@ Autowired注解的属性自动赋值、AOP)
bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解
[](
)Spring 中的 bean 的作用域有哪些?
-
singleton(单例模式,默认) : 每个容器中只有一个bean的实例,单例的模式由 Beanfactory自身来维护。该对象的生命周期是与 Spring IOC容器一致的(但在第一次被注入时才会创建)。
-
prototype (原型模式): 每次请求都会创建一个新的 bean 实例。在每次注入时都会创建个新的对象
-
request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
-
session:每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
-
application:bean被定义为在 Servletcontext的生命周期中复用一个单例对象(可以实现跨容器)
-
global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
[](
)Spring 中的单例 bean 线程安全吗?
存在安全问题的。Spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理,当多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题。
但是大多数bean都是无状态的(不具有数据存储功能),比如说controller、 service和dao层,我们一般只是调用里面的方法,多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。但是dao层会操作数据库 Connection, Connection是带有状态的,比如说数据库事务, Spring的事务管理器,需要我们进行处理。
因此,不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,可以参考一下方案:
-
使用 Threadloca把变量变为线程私有的,比如在dao层,可以使用Threadlocal为不同线程维护了一套独立的 connection副本,保证线程之间不会互相影响。
-
改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。
-
如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用 synchronized、OCK、CAS等这些实现线程同步的方法了。
[](
)Spring 框架中用到了哪些设计模式?
-
工厂设计模式: 由一个工厂类根据传入的参数,动态决定创建那个产品类。Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建bean 对象。
-
单例设计模式 : 保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring 中的 Bean 默认都是单例的。
-
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式(HandlerAdapter)适配Controller,对应的每一种Controller都有一种对应的适配器实现类。
-
代理设计模式 : Spring AOP 功能的实现。AOP把切面应用到对象并创建新的代理对象。
-
观察者模式:Spring的事件驱动模型使用的是观察着模式,Spring中Observer模式常用的地方是Listener的实现。
-
策略模式:Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource的接口来访问底层资源。
-
装饰器模式:动态地给一个对象添加额外的职责。Spring中类名包括Wrapper或Decorator使用了装饰器模式。
-
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
-
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
[](
)Spring事务的实现方式
Spring 管理事务的方式有几种?
-
编程式事务,在代码中硬编码。(不推荐使用)
-
声明式事务,在配置文件中配置(推荐使用)
声明式事务又分为:
-
基于XML的声明式事务
-
基于注解的声明式事务
说一下 Spring的事务机制
-
spring事务底层是基于数据库事务和AOP机制的(事务这个概念是数据库层面的, Spring只是基于数据库中的事务进行了扩展)
-
首先对于使用了@Transactional注解的bean,Spring会创建一个代理对象作为Bean
-
当调用代理对象的方法时,会先判断该方法上是否加了@ Transactional注解
-
如果加了,那么则利用事务管理器创建一个数据库连接,并把事务的自动提交设置为 false,然后再去执行原本的业务逻辑方法(sql)。
-
如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交
-
如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚
-
针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的 rollbackfor属性进行配置,默认情况下会对 Runtimeexception和Error进行回滚。
-
Spring事务的隔离级别对应的就是数据库的隔离级别
-
Spring事务的传播机制是 Spring事务自己实现的,也是 Spring事务中最复杂的
-
Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql
[](
)@Transactional注解了解吗?
Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
@Transactional(rollbackFor = Exception.class):
在@Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。
[](
)spring事务什么时候会失效?
spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了。常见情况有如下几种:@Transactional标识的方法只有被代理对象调用时,注解才会生效
-
发生自调用,类里面使用this调用本类的方法,此时这个this对象不是代理类,而是Userservice对象本身(解决方法很简单,让那个this变成 Euserservice的代理类即可)
-
方法不是public的,Transactional只能用于public的方法上,否则事务不会失效,如果要用在非public方法上,可以开启( Aspectj代理模式)。
-
异常被吃掉,事务不会回滚或者抛出的异常没有被定义,默认为 RuntimeException。
[](
)Spring 事务中的隔离级别有哪几种?
spring事务隔离级别就是数据库的隔离级别:外加一个默认级别
-
isolation_default(默认级别):使用后端数据库默认的隔离级别
-
read_uncommitted(读未提交读):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
-
read_committed(读以提交、不可重复读):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
-
repeatable_read(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
-
serializable(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
数据库的配置隔离级别是 Read Commited,而 Spring配置的隔离级别是 Repeatable Read,请问这时隔离级别是以哪个为准?
以 Spring配置的为准,如果 spring设置的隔离级别数据库不支持,效果取决于数据库
[](
)Spring 事务中哪几种事务传播行为?
多个事务方法相互调用时事务如何在这些方法间传播:
方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。
-
REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
-
SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
-
MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则拋出异常
-
REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务
-
NOT_SUPPORTED:以非事务方式执行如果当前存在事务,则挂起当前事务
-
NEVER:不使用事务,如果当前事务存在,则抛出异常
-
NESTED:如果当前事务存在,则在嵌套事务中执行,否则 REQUIRED的操作一样(开启一个事务)
NESTED和 REQUIRES_NEW的区别:
REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而 NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在 NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务
NESTED和 REQUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否 catch其异常,事务都会回滚而在 NESTED情况下,被调用方发生异常时,调用方可以 catch其异常,这样只有子事务回滚,父事务不受影响。
[](
)什么是bean的自动装配?自动装配有哪些方式?
在Spring框架中,在配置文件中设定了bean的依赖关系,Spring 容器能够自动装配相互合作的bean。这意味着容器不需要配置,能通过Bean工厂自动处理bean之间的协作,Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。
使用@Autowired注解自动装配的过程:
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,
<context:annotation-config />
。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
- 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
- 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
- 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用Autowire来配置自动装载模式。在Spring框架xml配置中共有5种自动装配:
-
no:默认的方式是不进行自动装配的,通过手工设置
ref
属性来进行装配bean。 -
byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
-
byType:通过参数的数据类型进行自动装配。
-
constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
-
autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
<!--byName-->
<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="byName"/>
<bean id="person" class="com.XXX.XXX.Person"/>
<!--byName-->
<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="byType"/>
<bean id="person" class="com.XXX.XXX.Person"/>
<!--construtor-->
<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="construtor"/>
<bean id="person" class="com.XXX.XXX.Person"/>
[](
)自动装配有哪些局限性?
-
重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。
-
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
-
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
[](
)Spring MVC的工作流程了解吗?
MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的Web层的开发,并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。
SpringMVC工作流程:
-
用户发送请求至前端控制器 Dispatcherservlet(用来处理HTTP请求与响应)
-
Dispatcherservlet 收到请求调用 Handler Mapping处理器映射器。
-
处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器及处理器拦截器(如果有则生成)并返回给 Dispatcherservlet。
-
Dispatcherservlet调用 HandlerAdapter处理器适配器
-
HandleraAapter经过适配调用具体的处理器(Controller,也叫后端控制器)
-
Controller执行完成返回 ModelAndView。
-
HandlerAdapter将 controller执行结果 ModelAndView返回给 Dispatcherservlet。
-
Dispatcherservlet将 Modelandview传给 ViewReslover视图解析器。
-
Viewreslover解析后返回具体View
-
Dispatcherservlet根据view进行渲染视图(即将模型数据填充至视图中)。
-
Dispatcherservle响应用户(浏览器)。
最后
我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](
)**
已经将知识体系整理好(源码,笔记,PPT,学习视频)
vlet。**
-
Dispatcherservlet将 Modelandview传给 ViewReslover视图解析器。
-
Viewreslover解析后返回具体View
-
Dispatcherservlet根据view进行渲染视图(即将模型数据填充至视图中)。
-
Dispatcherservle响应用户(浏览器)。
最后
我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](
)**
已经将知识体系整理好(源码,笔记,PPT,学习视频)
[外链图片转存中…(img-T2MwQf2P-1631173099826)]
[外链图片转存中…(img-LuM0KB3A-1631173099827)]
[外链图片转存中…(img-BFPVNjKG-1631173099828)]