vlambda博客
学习文章列表

这可能是最全面的Spring复习大杂烩了!

1.1 Spring特征

1.1.1 轻量

从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1M多的Jar文件里发布,并且Spring所需的处理开销是微不足道的。

1.1.2 控制反转(IOC)

  • Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系。Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。

  • Spring通过一种称作控制反转IOC的技术促进了低耦合

  • 当应用了IOC,一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象

1.1.3 面向切面(AOP)

Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开

" 横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。使用"横切"技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。AOP 主要应用场景有:

  1. Authentication 权限

  2. Caching 缓存

  3. Context passing 内容传递

  4. Error handling 错误处理

  5. Lazy loading 懒加载

  6. Debugging 调试

  7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准

  8. Performance optimization 性能优化

  9. Persistence 持久化

  10. Resource pooling 资源池

  11. Synchronization 同步

  12. Transactions 事务

1.1.4 容器

Spring包含并管理用用队形的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建,基于一个可配置原型,你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例,以及它们是如何相互关联的。

1.1.5框架

  • Spring可以将简单的组件配置组合成为复杂的应用。

  • 在Spring中,应用对象被生命式地组合,典型的是在一个XML文件里。

  • Spring也提供了很多基础功能(事务管理、持久化框架集成等),将应用逻辑的开发留给开发者。

1.2 Spring核心组件

1.2.1 Bean组件

组件作用

Bean组件在Spring中的Beans包下,为了解决三件事。Bean的创建,Bean的定义,Bean的解析。最关心的就是Bean的创建。

Bean的创建

  • 工厂模式的实现,顶层接口是:BeanFactory

  • 虽然最终实现类是DefaultListableBeanFactory,但是其上层接口都是为了区分在Spring内部对象的传递和转换的过程,对对象的数据访问所做的限制。

  • ListableBeanFactory:可列表的

  • HierarchicalBeanFactory:可继承的

  • AutowriteCapableBeanFactory:可自动装配的

  • 这四个接口,共同定义了Bean的集合,Bean之间的关系,Bean的行为。

Bean的定义

Bean的定义完整的描述在Spring配置文件中节点中,包括子节点等。在Spring内部它被转换成BeanDefinition对象,后续操作都是对这个对象操作。主要是BeanDefinition来描述

1.2.2 Context组件

在Spring中的context包下,为Spring提供运行环境,用以保存各个对象状态。

Context作为Spring的IOC容器,整合了大部分功能或说大部分功能的基础,完成了以下几件事:  1、标识一个应用环境  2、利用BeanFactory创建Bean对象  3、保存对象关系表  4、能够捕获各种事件ApplicationContext是context的顶级父类,除了能标识一个应用的基本信息外,还继承了五个接口,扩展了Context的功能。并且继承了BeanFactory,说明Spring容器中运行的主体对象是Bean,另外还继承了ResourceLoader,可以让ApplicationContext可以访问任何外部资源。

ApplicationContext子类

  1. ConfigurableApplicationContext:表示Context是可以修改的,在构建Context,用户可以动态添加或者修改已有的配置。

  2. WebApplicationContext:为Web准备的Context,可以访问ServletContext。

1.2.3 Core组件

访问资源

  1. 它包含了很多关键类,一个重要的组成部分就是定义的资源的访问方式,这种把所有资源都抽象成了一个接口的方式很值得学习。

  2. Resource接口封装了各种可能的资源类型,继承了InputStreamSource接口。加载资源的问题,也就是资源加载者的统一,由ResourceLoader接口来完成。默认实现是:DefaultResourceLoader

Core资源的加载

Core组件将解析等工作委托给了ResourcePatternResolver来完成,作为一个接头人,把资源的加载,解析和定义整合在了一起便于其他组件使用。

1.3 Spring常用注解

bean 注入与装配的的方式有很多种,可以通过 xml,get set 方式,构造函数或者注解等。简单易用的方式就是使用 Spring 的注解了,Spring 提供了大量的注解方式。

@Controller

  1. 用于标注控制层组件。

  2. 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象。

  3. 分发处理器将会扫描使用了该注解的方法,并检测该方法是否用了@RequestMapper注解。

  4. 可以把Request请求header部分的值绑定到方法的参数上。

@RestController

相当于@Controller和@responseBody的组合效果

@Component

泛指组件,当组件不好归类的时候,我们可以用这个注解进行标注

@Repository

用于注解dao层,在daoImpl类上面注解

@Service

用于标注业务层组件

@ResponseBody

  1. 异步请求

  2. 该注解用于将Controller的方法返回值对象,通过当前的HttpMessageConverter转换为指定格式后,写入Response对象的Body数据区

  3. 返回的数据不是HTML标签的页面,而是其他某种格式的数据时(入xml、Json)使用

@RequestMapping

包括所有请求方式,例如:PostMapping(增)、DeleteMapping(删)、PutMapping(改)、GetMapping(查)---RESTful风格

@Autowired

他可以对类成员变量、方法及够骚函数进行标注,完成自动装配的工作,通过@Autowired的使用来消除set、get方法

@PathVariable

用于请求URL中的模板变量映射到功能处理方法的参数上,即取出URL模板中的变量作为参数

@RequestParam

主要用于在SpringMVC后头控制层获取参数,类似一种request.getParameter(“name”)

@RequestHeader

可以把Request请求header其部分的值绑定到方法参数上

@ModelAttribute

该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时先执行@ModelAttribute方法。

@SessionAttribute

将值放到session作用域中,写在class上面

@CookieValue

用来获取Cookie中的值

1.4 Spring的优点

  1. spring属于低侵入式设计,代码的污染极低;

  2. spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;

  3. Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。

  4. spring对于主流的应用框架提供了集成支持。

1.5 SpringAOP的理解

  • OOP面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

  • AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。

  • AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

    1. AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

    2. Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

    3. 静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

      InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):proxy是最终生成的代理实例;  method 是被代理目标实例的某个具体方法;  args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

  • ①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。

  • ②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

1.6 SpringIOC理解

  1. IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。

  2. 最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

  3. Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

  4. 将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。

Spring时代我们一般通过XML文件来配置Bean,后来开发人员觉得用XML文件来配置不太好,于是Sprng Boot注解配置就慢慢开始流行起来。

这可能是最全面的Spring复习大杂烩了!

1.7 BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

  • ①继承MessageSource,因此支持国际化。

  • ②统一的资源文件访问方式。

  • ③提供在监听器中注册bean的事件。

  • ④同时加载多个配置文件。

  • ⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

1.8 Spring Bean生命周期

首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

Spring上下文中的Bean生命周期也类似,如下:

  1. 实例化Bean:

    对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

  2. 设置对象属性(依赖注入):

    实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

  3. 处理Aware接口:

    接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

    ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

    ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

    ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

  4. BeanPostProcessor:

    如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

  5. InitializingBean 与 init-method:

    如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

  6. 如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

    以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

  7. DisposableBean:

    当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

  8. destroy-method:

    最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。


1.9 Spring基于xml注入bean的几种方式

  1. Set方法注入;

  2. 构造器注入:①通过index设置参数的位置;②通过type设置参数类型;

  3. 静态工厂注入;

  4. 实例工厂;

1.10 Spring框架中用到了哪些设计模式

  1. 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

  2. 单例模式:Bean默认为单例模式。

  3. 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

  4. 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。

1.11 Spring事务的实现方式和实现原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

(1)Spring事务的种类:

spring支持编程式事务管理和声明式事务管理两种方式:

①编程式事务管理使用TransactionTemplate。

②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。

声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

(2)spring的事务传播行为:

spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

(3)Spring中的隔离级别:

① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。