能简单说一下你对Spring框架的理解么?
Spring是一种轻量级框架,用于提高开发人员的开发效率和可维护性。它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块包括:核心容器、数据访问/集成、响应式 web 编程、AOP(面向切面编程)、工具、消息和测试模块。
下图对应的是Spring 4.x的版本,目前最新的5.x版本中Web模块的Portlet组件已经被废弃掉,同时增加了用于异步响应式处理的WebFlux组件。
对AOP的理解
AOP就是 面向切面编程, 是 OOP(面向对象编程)的补充,在 OOP 中, 我们把类(class)作为基本单元,而在 AOP 中基本单元是 Aspect(切面) ,切面里封装的是影响多个类的公共行为,比如日志、异常处理、记录方法耗时等,它们与业务无关,却被不同的业务模块所共同调用。Spring AOP的做法就是在程序运行期间动态的将某段代码(切面)切入到指定位置再运行,它是一种编程思想。
Aspect 切面代码段里包括切点和Advice,切点指明织入到哪些对象的哪些位置;Advice更具体地指定织入的逻辑和时机(方法前、后、返回时、出异常时)
一般会有疑问,上面说的情况,用普通的【抽离出公共代码,放在独立的类独立的方法中,然后再调用】方式也可以实现,为什么要这么复杂呢?
回答:上面的情景,比如日志记录,大致有四种处理方法。
1、【重复性复制粘贴代码】:这种就不说了最低效,耦合性太高。
2、【抽离出公共代码,放在独立的类独立的方法中,然后再调用】:可以解决问题,但比较原始,调用语句散布在各处地方,如果想改变调用的时机或者删除这个调用,所有位置都需要处理。
3、【拦截器】:拦截器只作用在controller层,但service层也是有日志记录的需求的。
4、【AOP】:单独定义一个切面(代码段),与业务组件没有任何联系,也不需要与业务组件去调用,而是用框架提供的织入方式,在某些时机把切面织入到目标对象里,时机包括多种取决于框架(Spring AOP框架默认在运行时织入)。
时机包括编译时织入(需使用特殊的编译器)、装载时织入(需使用特殊的类装载器)、运行时织入(需为目标生成代理对象)
AOP的实现
AOP实现的原理是代理,AOP代理主要分为静态代理和动态代理。
-
静态代理的代表为AspectJ,它是一种独立的语言,有一个专门的编译器,在编译期织入代码
-
动态代理则以Spring AOP为代表,使用纯Java实现,在运行时通过 动态代理 的方式织入代码,只支持方法类型的切点。大多数业务场景都是在方法上织入,已经足够了;如果有情况处理不了,Spring AOP是集成了AspectJ的,可以在里面使用它。
动态代理方案:
-
JDK动态代理:Spring AOP默认采用的方式,利用反射机制生成一个实现某 接口 的匿名类,在调用具体方法前调用 InvokeHandler 来处理,他有一个限制,就是它只能为接口创建代理实例,那么对于没有通过接口定义业务方法的类,就要用CGLIB动态代理了。
-
CGLib动态代理:当目标对象不存在接口时,Spring AOP 会采用此种方式,通过继承方式实现代理,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
-
对IOC的理解
IOC(Inversion Of Controll,控制反转)是一种设计思想,本来创建对象需要我们在程序中自己new,现在交由Spring去管理对象的创建和依赖关系,可以把IOC看作一个对象工厂,等我们需要用对象的时候,从工厂里边获取就行了。
实现控制反转的方法是依赖注入(DI),我们需要在元数据中描述如何创建它们以及他们的依赖关系,元数据可以通过 XML,Java 注解或 Java 代码提供。
依赖注入可以通过三种方式完成:构造函数注入、setter 注入、接口注入。(Spring仅用前两个)
使用IOC的好处:「将对象集中统一管理」并且「降低耦合度」
spring中有哪几种IOC容器:BeanFactory 、ApplicationContext
Spring IOC 管理的对象就叫 Bean
Spring容器的启动流程
(1)初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中。
(2)将配置类的BeanDefinition注册到容器中。
(3)调用refresh()方法刷新容器。
Spring Bean的生命周期
实例化 Instantiation --> 属性赋值 Populate --> 初始化 Initialization --> 销毁 Destruction
说一下Spring中Bean的作用域(scope)
(1)singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
(2)prototype:为每一个bean请求创建一个实例。
(3)request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
Spring框架中都用到了哪些设计模式?
(1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
(2)单例模式:Bean默认为单例模式
(3)策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
(4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
(5)模板方法:可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,用来解决代码重复的问题。比如RestTemplate, JmsTemplate, JpaTemplate
(6)适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式,Spring MVC中也是用到了适配器模式适配Controller
(7)观察者模式:Spring事件驱动模型就是观察者模式的一个经典应用。
(8)桥接模式:可以根据客户的需求能够动态切换不同的数据源。比如我们的项目需要连接多个数据库,客户在每次访问中根据需要会去访问不同的数据库。