Spring

Spring 框架

Spring 是什么?

Spring 是一个轻量级的 IoC  AOP 容器框架。是为 Java 应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于 XML 的配置.基于注解的配置. 基于 Java 的配置。

主要由以下几个模块组成:

Spring Core:核心类库,提供 IOC 服务;

Spring Context:提供框架式的 Bean 访问方式,以及企业级功能(JNDI. 定时任务等);

Spring AOP:AOP 服务;

Spring DAO:对 JDBC 的抽象,简化了数据访问异常的处理; Spring ORM:对现有的 ORM 框架的支持;

Spring Web:提供了基本的面向 Web 的综合特性,例如多方文件上传; Spring MVC:提供面向 Web 应用的 Model-View-Controller 实现。

Spring 的优点?

(1) Spring 属于低侵入式设计,代码的污染极低;

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

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

(4) Spring 对于主流的应用框架提供了集成支持。

Spring  AOP 理解?

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

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

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

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

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

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

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

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

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

InvocationHandler 的

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

Spring  IOC 理解?

(1) IOC 就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到 Spring 容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松

散耦合,也利于功能的复用。DI 依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖 IoC 容器来动态注入对象需要的外部资源。

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

(3) Spring  IOC 有三种注入方式 :构造器注入.setter 方法注入.根据注解注入。

IOC 让相互协作的组件保持松散的耦合,而 AOP 编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

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 则是自动注册。

请解释 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)方法。由于这个方法是在 Bean 初始化结束时调用的,所以可以被应用于内存或缓存技术;

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

(6) 如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;

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

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

解释 Spring 支持的几种 bean 的作用域。

Spring 容器中的 bean 可以分为 5 个范围:

(1) singleton:默认,每个容器中只有一个 bean 的实例,单例的模式由 BeanFactory 自身来维护。

(2) prototype:为每一个 bean 请求提供一个实例。

(3) request:为每一个网络请求创建一个实例,在请求完成以后bean 会失效并被垃圾回收器回收。

(4) session:与 request 范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后bean 会随之失效。

(5) global-session:全局作用域,global-session  Portlet 应用相关。当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在global-session 中。全局作用域与 Servlet 中的 session 作用域效果相同。

使用注解之前要开启自动扫描功能

 @Configuration 把一个类作为一个 IoC 容器,它的某个方法头上如果注册了@Bean,就会作 

 为这个 Spring 容器中的 Bean。

 @Scope 注解 作用域

 @Lazy(true) 表示延迟初始化

 @Service 用于标注业务层组件.

 @Controller 用于标注控制层组件(如 struts 中的 action)

 @Repository 用于标注数据访问组件,即 DAO 组件。

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

@Scope 用于指定 scope 作用域的(用在类上)

@PostConstruct 用于指定初始化方法(用在方法上) @PreDestory 用于指定销毁方法(用在方法上)

@Resource 默认按名称装配,当找不到与名称匹配的 bean 才会按类型装配。

Spring 框架中的单例 Beans 是线程安全的么?

Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的 Spring bean 并没有可变的

状态(比如 Serview 类和 DAO ),所以在某种程度上说 Spring 的单例 bean 是线程安全的。如果你的 bean 有多种状态的话比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。

10 Spring 如何处理线程并发问题?

在一般情况下,只有无状态的 Bean 才可以在多线程环境下共享,在 Spring 中,绝大部分 Bean 都可以声明为 singleton 作用域,因为 Spring 对一些 Bean 中非线程安全状态采用 ThreadLocal 进行处理,解决线程安全问题。

ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而 ThreadLocal 采用了“空间换时间”的方式。

ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装 ThreadLocal。

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

(1) Set 方法注入;

(2) 构造器注入:1.通过 index 设置参数的位置;2.通过 type 设置参数类型;3.通过name 注入

(3) 静态工厂注入;

(4) 实例工厂;

12 Spring 的自动装配:

在Spring 中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用 autowire 来配置自动装载模式。

Spring 框架 xml 配置中共有 5 种自动装配:

(1) no:默认的方式是不进行自动装配的,通过手工设置 ref 属性来进行装配 bean。

(2) byName:通过 bean 的名称进行自动装配,如果一个 bean  property 与另 bean 的 name 相同,就进行自动装配。

(3) byType:通过参数的数据类型进行自动装配。

(4) constructor:利用构造函数进行装配,并且构造函数的参数通过 byType 进行装配。

(5) autodetect:自动探测,如果有构造方法,通过 construct 的方式自动装配,否则使用 byType 的方式自动装配。

基于注解的方式:

使用@Autowired 注解来自动装配指定的 bean。在使用@Autowired 注解之前需要在Spring 配置文件进行配置<context:annotation-config />。在启动 spring IoC 时,

容器自动装载了一个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描@Autowied.@Resource @Inject 时,就会在 IoC 容器自动查找需要的 bean,并装配给该对象的属性。在使用@Autowired 时,首先在容器中查询对应类型的 bean:如果查询结果刚好为一个,就将该 bean 装配给@Autowired 指定的数据;如果查询的结果不止一个,那么@Autowired 会根据名称来查找;

 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用 required=false。

@Autowired 可用于:构造函数.成员变量.Setter 方法注:@Autowired 和@Resource 之间的区别

(1) @Autowired 默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在

(可以设置它 required 属性为 false)。

(2) @Resource 默认是按照名称来装配注入的,只有当找不到与名称匹配的 bean 才会按照类型来装配注入。

13 Spring 框架中都用到了哪些设计模式?

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

(2) 单例模式:Bean 默认为单例模式。

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

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

(5) 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,

所有依赖于它的对象都会得到通知被制动更新,如 Spring 中 listener 的实现

--ApplicationListener。

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

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

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

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

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

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

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

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

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

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

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

(3) Spring 中的隔离级别:

15 Spring 框架中有哪些不同类型的事件?

Spring 提供了以下 5 种标准的事件:

(1) 上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的 refresh()方法时被触发。

(2) 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext  Start()方法开始/重新开始容器时触发该事件。

(3) 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext  Stop()方法停止容器时触发该事件。

(4) 上下文关闭事件ContextClosedEvent): ApplicationContext 被关闭时触发该事件。容器被关闭时,其管理的所有单例 Bean 都被销毁。

(5) 请求处理事件RequestHandledEvent): Web 应用中,当一个http 请求request)结束触发该事件。

如果一个 bean 实现了 ApplicationListener 接口,当一个ApplicationEvent 被发布以后,bean 会自动被通知。

16 解释一下 Spring AOP 里面的几个名词

(1) 切面Aspect):被抽取的公共模块,可能会横切多个对象。在 Spring AOP 中,切面可以使用通用类(基于模式的风格) 或者在普通类中

@AspectJ 注解来实现。

(2) 连接点(Join point):指方法,在 Spring AOP 中,一个连接点 总是 代表一个方法的执行。

(3) 通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”.“before”和“after”等通知。许多 AOP 框架,包括 Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

(4) 切入点(Pointcut):切入点是指 我们要对哪些 Join point 进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截 add*.search*。

(5) 引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring 允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使 bean 实现 IsModified 接口,以便简化缓存机制。

(6) 目标对象(Target Object): 被一个或者多个切面aspect)所通知advise)的对象。也有人把它叫做 被通知adviced) 对象。 既然 Spring AOP 是通过运行时代理实现的,这个对象永远是一个 被代理proxied)对象。

(7) 织入Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring 是在运行时完成织入。

 

5.17 Spring 通知有哪些类型?

(1) 前置通知Before advice):在某连接点join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

(2) 返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

(3) 抛出异常后通知After throwing advice):在方法抛出异常退出时执行的通知。

(4) 后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(5) 环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。

也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行 环绕

通知是最常用的一种通知类型。大部分基于拦截的 AOP 框架,例如 Nanning 和 JBoss4,

 
   

都只提供环绕通知。

相信自己,坚信自己的目标,去承受常人承受不了的磨难与挫折,不断的努力去奋斗,最终的成功就会是你
原文地址:https://www.cnblogs.com/Valuez/p/13302025.html