Spring 概述
什么是 spring?
spring 是一个轻量级的 java 开发框架,它的呈现简化了企业级利用开发的难度,是 Java 开发人员更专一于业务代码逻辑的编写。它有两个特点:IOC 管制翻转和 AOP 面向切面编程。
谈谈 IOC 和 AOP
IOC(管制翻转)
平时咱们须要应用对象,都是本人 new 一个进去。这样在咱们我的项目中,就会呈现大量的冗余对象。而 IOC 管制翻转所在的事件,就是咱们之前本人 new 对象的操作取代了,对象由 spring 的 IOC 容器创立并治理。咱们须要用到一个对象的时候,只须要向 IOC 容器的 beanFactory 索取即可。总体来说,就是将对象创立的权力从程序员手上,交到了 IOC 容器手中。
AOP(面向切面编程)
AOP 是对 OOP(面向对象编程)的一种补充,面向对象编程是将事务的特色和行为形象成一个个对象,而面向切面编程则是在一个个对象的根底上的进一步形象。找寻这些对象都须要做的事件,而后就成一把刀一样在这些对象上切出一个面,来退出对象都须要做的事件。AOP 是通过动态代理或者动静代理来实现的,其余动静代理更为灵便,分为 Java 自带的代理接口和 Cglib 动静代理。咱们通常应用 AOP 来实现日志、事务、安全检查相干的操作。
Spring 由哪些模块组成?
- spring core:提供了框架的根本组成部分,如 IOC、DI 等性能。
- spring beans:提供了 BeanFactory,是工厂模式的一个经典实现,spring 将治理对象称为 bean。
- spring context:构建与 core 封装包根底上的 context 封装包,提供了一种框架式的对象拜访办法。
- Spring jdbc:拱了一个 JDBC 的形象层,打消了繁琐的 JDBC 编码和数据库厂商特有的错误代码解析,用于简化 JDBC 的操作。
- Spring AOP:提供了面对想切面的编程实现,让你能够自定义拦截器、切点等。
- Spring web:提供了针对 web 开发的继承个性,例如文件上传,利用 servlet listeners 进行 IOC 容器初始化和针对 web 的 applicationContext。
- Spring test:次要为测试提供反对的,反对应用 Junit 或 TestNG 对 Spring 组件进行单元测试和集成测试。
Spring 框架中都用到了哪些设计模式?
- 工厂模式:BeanFactory 就是简略工厂模式的体现的,用来创建对象的实例。
- 单例模式:Bean 默认为单例模式。
- 代理模式:Spring 的 AOP 面向切面编程就用来到了 JDK 的动静代理和 CGLIB 动静代理。
- 模板办法:比方,RestTemplate、JpaTemplate 都用了模板办法,用来解决代码反复的问题。
- 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都会失去告诉被制动更新,如 Spring 中 listener 的实现
ApplicationListener
。
Spring 如何治理事务的?
Spring 的事务申明有两种形式:编程式和申明式。
spring 次要是通过“申明式事务”的形式对事务进行治理,即在配置文件、注解进行事务申明,通过 AOP 将事务切面切入程序,最大的益处是大大减少了代码量。
Spring IOC 容器配置 Bean 的形式?
- XML 文件
bean
标签的形式 - 注解的形式
- java Config 代码类的形式
Bean 是如何被治理的?【重点】
在 spring 框架中,一旦把一个 bean 纳入到 Spring IOC 容器之中,这个 bean 的生命周期就会交由容器进行治理,个别担当管理者角色的是 BeanFactory 或 ApplicationContext。认识一下 Bean 的生命周期流动,对更好的利用它有很大的帮忙。
详情来说次要有四个阶段:实例化、初始化、应用、销毁。
- 首先容器启动后,会对 scope 为 singleton 且非懒加载的 bean 进行实例化。
- 依照 bean 定义信息配置信息,注入所有的属性。
- 如果 bean 实现了 BeanNameAware 接口,会回调该接口的 setBeanName()办法,传入该 Bean 的 id,此时该 bean 就取得了本人在配置文件中的 id。
- 如果 Bean 实现 BeanFactoryAware 接口,会回调该接口的 setBeanFactory()办法,传入该 bean 的 BeanFactory,这样该 bean 就取得了本人所在的 BeanFactory。
- 如果 Bean 实现了 ApplicationContextAware 接口,会回调该接口的 setApplicationContext()办法,传入该 Bean 的 ApplicationContext,这样该 bean 就取得了本人所在的 ApplicationContext。
- 如果有 Bean 实现了 BeanPostProcessor 接口,则会回调该接口的 postProcessBeforeInitialzation()办法。
- 如果 Bean 实现了 InitializingBean 接口,则会回调该接口的 afterPropertiesSet()办法。
- 如果 Bean 配置了 init-method 办法,则会执行 init-method 配置的办法。
- 如果有 Bean 实现了 BeanPostProcessor 接口,则会回调该接口的 postProcessAfterInitialization()办法。
- 通过流程 9 之后,就能够正式应用该 bean 了,对于 scope 为 singleton 的 bean,spring 的 ioc 容器中会缓存一份该 bean 的实例,而对于 scope 为 prototype 的 bean,每次被调用都会 new 一个新的对象,申明周期就交给调用方治理了,不再是 Spring 容器进行治理了。
- 容器敞开后,如果 Bean 实现了 DisposableBean 接口,则会回调该接口的 destroy()办法。
- 如果 Bean 配置了 destroy-method 办法,则会执行 destroy-method 配置的办法,至此,整个 Bean 的生命周期完结了。
Spring 中的主动拆卸有哪些限度?
- 如果应用了结构器注入或者 settter 注入,那么将笼罩主动拆卸的依赖关系。
- 根本数据类型的值、字符串字面量、类字面量无奈应用主动拆卸来注入。
- 优先应用显式的拆卸来进行更准确的依赖注入而不是应用主动拆卸。
Spring 中 Bean 的作用域有哪些?
- singleton 作用域: 在 spring IOC 容器中仅仅存在一个 Bean 实例,Bean 是以单例形式存在的,为默认值。
- prototype 作用域:每次从容器中调用 Bean 时,都返回一个新的实例,即每次调用 getBean()时,相当于执行 newXXXBean().
- request 作用域:每一个 http 申请中的 bean 是单例的,该作用域仅实用于 WebApplicationContext 环境
- session 作用域:每一个 session 中的 bean 是单例的,不同 Session 应用不同的 Bean,仅实用于 WebApplicationContext 环境
- globalSession 作用域:个别用于 Portlet 应用环境,该作用域仅实用于 WebApplicationContext 环境。
什么是 IOC 和 DI?DI 是如何实现的?
IOC 是管制反转的意思,之前没有引入 IOC 容器时,退出对象 A 依赖于对象 B,那么对象 A 在创立初始化或者运行到某一点的时候,须要用到 B 对象时,就须要咱们手动本人去创立一个 B 对象。这个时候无论是创立 B 对象,还是应用 B 对象的控制权都在咱们本人的手上。然而在引入 IOC 容器之后,情景就实现变动了,当对象 A 运行过程中须要用到对象 B 的时候,不是须要咱们本人再手动创立一个 B 对象了,而是 IOC 容器会主动创立一个 B 对象,帮忙咱们注入到 A 对象中。通过前后的比照,咱们不难发现。对象 A 获取依赖对象 B 的过程,由被动行为编程了被动行为。对象的创立、管理权,从咱们手上转移到了 IOC 容器中了。这就是 IOC 管制翻转。
对于 DI 依赖注入:其实 DI 与 IOC 管制反转是从不同方面形容的同一件事件,都是指将对象的创立、管理权从使用者的手上,通过依赖注入到 IOC 容器中。
IOC 的优缺点
长处
升高了类之间的耦合,可维护性失去了进步。
毛病
- 因为 IOC 容器中对象的生成是通过反射造成的,所以在运行效率上会有一些损失。
- 要做一些额定的配置工作
你如何了解 AOP 中失去连接点(Joinpoint)、切点(Pointcut)、加强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?
- 连接点:程序执行的某个特定地位(如:某个办法调用前、调用后,办法抛出异样后)。一个类或一段程序代码领有一些具备边界性质的特定点,这些代码中的特定点就是连接点。Spring 仅反对办法的连接点。
- 切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查问条件,一个切点能够匹配多个连接点。Spring AOP 的规定解析引擎负责解析切点所设定的查问条件,找到对应的连接点。
- 加强(Advice):加强是植入到指标类连接点上的一段程序代码。Spring 提供的加强连贯口都是带方位名的。如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等。
- 引介(Introduction):引介是一种非凡的加强,它为类增加一些属性和办法。这样,即便一个业务类本来没有实现某个接口,通过引介性能能够动静的为该业务类增加接口的实现逻辑。让业务类成为这个接口的实现类。
-
织入(Weaving):织入是将加强增加到指标类具体连接点上的过程,AOP 有三种织入形式:
- 编译期织入:须要非凡的 Java 编译期(例如 AspectJ 的 ajc)
- 装载期织入:要求应用非凡的类加载器,在装载类的时候对类进行加强
- 运行时织入:在容许时为指标生成代理实现加强。spring 采纳动静代词的形式实现了运行时织入,而 AspectJ 采纳了编译期织入和装载期织入的形式。
- 切面(Aspet):切面是由切点和加强(引介)组成的,它包含了对横切关注性能的定义,也包含了对连接点的定义。
Spring 主动拆卸的形式有哪些?
- no:不进行主动拆卸,而是手动设置 Bean 的依赖关系
- byName:依据 Bean 的名字进行主动拆卸
- byType:依据 Bean 的类型进行主动拆卸
- constructor:相似于 byType,不过是利用于结构器的参数,如果正好有一个 Bean 与结构器的参数类型雷同则能够主动拆卸,否则会导致谬误。
- autodetect:如果有默认的结构器,这通过 constructor 的形式进行主动拆卸,否则应用 byType 的形式进行主动拆卸。
Spring 中如何应用注解来配置 Bean?有哪些相干的注解?
在启动类上增加 @EnableAutoConfiguration 或者 @SpringBootApplication 来开启主动配置,而后应用以下的注解来标注须要由 Spring IOC 容器进行对象托管的类。
- @Component:其余所有类
- @Controller:controller 控制器
- @Service:service 业务逻辑层
- @Repository:dao 数据交互层
这几个注解的作用其实都是雷同的,都是将类注入到 ioc 容器中,只是为了不便区别字面上有所不同罢了。
Spring MVC 的工作流程
- 客户端的所有申请都叫给前端管制 dispatcherServlet 来解决,它会负责调用零碎的其余模块来真正解决用户的申请。
- 前端控制器 DispatcherServlet 收到申请后,将依据申请的信息以及 HandlerMapping 的配置找到解决该申请的对应 Handler 处理器。
- spring 会通过 HandlerAdapter 对该处理器进行封装,而后用对立的接口对各种 Handler 中的办法进行调用。
- Handler 实现对用户申请的解决后,会返回一个 ModelAndView 对象给前端控制器 DispatcherServlet。
- DispatcherServlet 借助逻辑视图解析器 ViewResolver 来解析刚返回失去的 ModelAndView 对象
- 最初拿到真正的视图对象,浏览器对模型数据进行渲染
- 客户端失去响应,可能是一个一般的 html 页面,也可能是 xml 或者是 JSON 字符串,还能够是一张图片或者 PDF 文件。
ApplicationContext 通常的实现是什么?
- FlieSystemXmlApplciationContext: 此容器从一个 XML 文件中加载 bean 是的定义,XML bean 配置文件的全路径名必须提供给他的构造函数。
- ClassPathXmlApplicationContext: 此容器也从一个 XML 文件中加载 Beans 的定义,这里,你须要正确设置 classpath,因为这个容器将在 classpath 外面找到 bean 配置。
- WebXmlApplicationContext:此容器加载一个 XML 文件,此文件定义了一个 web 利用的所有 bean。
Bean 工厂和 APlication contexts 有什么区别?
- 相同点:两者都是通过 xml 配置文件加载 bean
- 不同点:applicationContext 相比于 BeanFactory,提供了更多的扩大性能。BeanFactory 是提早加载,如果 Bean 的某一个属性没有注入,BeanFactory 加载后,直至第一次应用调用 getBean 办法才会抛出异样。而 ApplicationContext 则在初始化本身就进行了效验,这样有利于查看说依赖属性是否注入。所以通常状况下咱们抉择应用 ApplicationContext。
spring 有几种依赖注入形式
-
变量注入
- 间接在变量下面应用 @Autowired 的既是变量注入
- 长处就是注入形式简略,十分简洁。
- 毛病:注入的对象不能用 final 润饰;可能会导致循环依赖的呈现;对于 IOC 容器以外的环境,除了应用反射来提供它须要的依赖,无奈复用该实现类;
-
结构器注入
- 显式注明必须强制注入,通过强制指明依赖注入来保障这个类的运行,防止出现空指针异样。
- 注入对象能够应用 final 润饰。
- 非 IOC 容器环境也能够应用 new 实例化该类的对象。
- 防止了循环依赖,如果真的存在循环依赖,spring 我的项目启动的时候就会报错。
- 毛病就是当咱们须要注入的对象过多的时候,构造函数的代码会显得十分的臃肿。
-
setter 办法注入
- 依赖注入中应用的依赖是可选的,抉择依赖的意思是注入的依赖是能够为 NULL。
- 容许在类结构实现后从新注入
- 毛病就是注入对象不能应用 final 润饰
总结:如果注入的属性是必选的属性,则通过结构器注入的形式;如果注入的属性是可选的,则通过 setter 注入的形式;至于变量注入,不倡议应用,尽管很省劲。
什么是 spring beans?
咱们的 spring 应用程序就是由一个个 spring beans 组成的,它们通过注解或者 xml 配置文件的形式定义,而后注入到的 IOC 容器中,由 IOC 容器治理整个生命周期。
spring 中的 bean 是线程平安的吗?
首先 spring IOC 容器自身并没有提供线程安全策略,因而咱们对于 bean 的线程平安问题,咱们须要联合具体的 bean 作用域来说:
- singleton:单例 bean,不会创立新的 bean,所有的线程都专用一个 bean 对象,因而可能会存在线程平安问题。
- prototype:原型 bean,因为每次都会创立一个 bean 对象,所以不会呈现线程平安问题。
实际上大部分理论 spring bean 都是无状态的,即无需进行数据保留操作,只是进行数据的查问。这个时候即便是单例 bean 也是线程平安的,然而如果要进行数据保留的一些操作,这个时候就须要咱们开发者本人对线程平安进行一些保障操作了。例如将singleton
变为prototype
。
Spring 如何解决线程并发问题?
- 个别状况下,只有无状态的 bean 才能够再多线程环境下共享,在 Spring 中,绝大部分 bean 都是以 singleton 申明的作用域,所以可能存在线程平安问题。所以咱们能够采纳 ThreadLocal 和线程同步机制来解决线程平安问题。
- ThreadLocal 采纳了空间换工夫的做法,为每一个线程提供一个独立的变量正本,从而隔离了多个线程对于对一个变量资源的拜访。
- 而线程同步机制则是对于可能存在线程平安问题的资源进行加锁,不同的线程在拜访加锁资源之前都须要获取锁资源,没有获取到的须要进行期待。这样就保障了同时只有一个线程对资源进行操作,也就解决了多线程资源并发的问题。然而因为要期待锁资源,所以是一种“工夫换空间”的做法。
主动拆卸有哪些局限性?
- 重写:你仍须要和配置来定义依赖,意味着重要重写主动拆卸。
- 根本数据类型:你不能主动拆卸简略的属性,如根本数据类型,String 字符串和类。
- 含糊个性:主动状态不如显示拆卸准确,如果有可能还是倡议应用显示拆卸。
你可始终了 spring 中注入一个 null 和一个空字符串嘛?
能够
@Autowired 和 @Resource 之间有什么区别?
- @Autowired 默认是依照类型进行拆卸注入的,、
- 而 @Resource 默认是依照名称来拆卸注入的,只有当找不到名称匹配的 bean 才会依照类型来拆卸。
@Qualifier 注解有什么用?
用来配合 @Autowired 注解更加精准的指定拆卸哪个 bean,因为 @AutorWried 是依照类型进行拆卸的,如果有多个同类型的 bean 须要被拆卸,单单应用 @AutoWried 注解是不行的,须要通过增加 @Qualifier 注解来指定 name 拆卸。
@RequestMapping 注解有什么用?
@RequestMapping 注解用于将特定 HTTP 申请办法映射到将解决响应申请的控制器重的特定类和特定办法。
Spring 事务的实质
spring 事务的实质其实就是对数据库事务的反对,如果没有数据库的事务反对,spring 是无奈提供事务性能的,真正的数据库层的事务提交和回滚是通过 binlog 或者 redo log 实现的。
说一下 Spring 的事务流传行为
spring 事务的流传行为就是说,当多个事务同时存在的时候,spring 如何解决这些事务的行为:
propagation_required
:如果以后没有事务,就创立一个新事务,如果以后存在事务,就退出该事务,该设置是最罕用的设置。propagation_supports
:反对以后事务,如果以后存在事务,就退出该事务,如果以后不存在事务,就以非事务运行。propagation_mandatory
:反对以后事务,如果以后存在事务,就退出该事务,如果以后不存在事务,就抛出异样。propagatin_requires_new
:创立新的事务,无论以后是否曾经存在事务,都会创立新的事务。propagation_not_supported
:以非事务形式执行操作,如果以后存在事务,就把以后事务挂起。propagation_never
:以非事务形式执行,如果以后存在事务,则抛出异样。propagation_nested
:如果以后存在事务,则在嵌套事务内执行。如果以后没有事务,这创立一个新的事务。
说一下 spring 的事务隔离?
spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(应用数据库的设置),其余四个隔离级别和数据库的隔离级别统一:
- ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
- SOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其余事务读取(会呈现幻读、脏读、不可反复读);
- ISOLATION_READ_COMMITTED:提交读,一个事务提交后能力被其余事务读取到(会造成幻读、不可反复读),SQL server 的默认级别;
- ISOLATION_REPEATABLE_READ:可反复读,保障屡次读取同一个数据时,其值都和事务开始时候的内容是统一,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
- ISOLATION_SERIALIZABLE:序列化,代价最高最牢靠的隔离级别,该隔离级别能避免脏读、不可反复读、幻读。
脏读:示意一个事务可能读取另一个事务中还未提交的数据。比方,某个事务尝试插入记录 A,此时该事务还未提交,而后另一个事务尝试读取到了记录 A。
不可反复读:是指在一个事务内,屡次读同一数据后果不统一。
幻读:是指在一个事务内,屡次读取的数据条数不统一。
Spring AOP and AspectJ AOP 有什么区别?AOP 都有哪些实现形式?
AOP 实现的关键在于代理模式,AOP 代理模式次要分为动态代理和动静代理。动态代理代表就为 AspectJ,而动静代理则以 Spring AOP 为代表。
- AspectJ 是动态代理的加强,所谓动态代理,就是 AOP 框架会在编译阶段生成 AOP 代理类,因而也称为编译时加强,他会在编译阶段将 AscpectJ(切面)织入到 Java 字节码中,运行的时候就是加强之后的 aop 对象。
- spring aop 应用的是动静代词,所谓的动静代词就是说 AOP 框架不会去批改字节码,而是每次运行时在内存中长期为办法生成一个 aop 对象,这个 aop 对象蕴含了对象的全副办法,并且在特定的切点还做了加强解决,并回调原对象的办法。
JDK 动静代理和 CGLIB 动静代理的区别?
- JDK 代理只能对实现接口的类生成代理;CGLib 是针对类实现代理,对指定的类生成一个子类,并笼罩其中的办法,这种通过继承类的实现形式,不能代理 final 润饰的类。
- JDK 代理应用的是反射机制实现 aop 的动静代理,CGLib 代理应用字节码解决框架 ASM,通过批改字节码生成子类。所以 jdk 动静代理的形式创立代理对象效率较高,执行效率较低,CGLib 创立效率较低,执行效率高。
- JDK 动静代理机制是委托机制,具体说动静实现接口类,在动静生成的实现类外面委托 hanlder 去调用原始实现类办法,CGLib 则应用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是能够赋值给被代理类的,如果被代理类有接口,那么代理类也能够赋值给接口。
动静代理和动静代理的区别?
动态代理与动静代理区别在于生成 AOP 代理对象的机会不同,动态代理在字节码生成的时候就曾经存在代理类了,而动静代理切实字节码文件生成后,内存中动静增加代理对象的。