关于后端:面试题Spring-面试集

49次阅读

共计 19695 个字符,预计需要花费 50 分钟才能阅读完成。

Spring 面试集

基于 Spring Framework 4.x 总结的常见面试题,零碎学习倡议还是官网文档走起:https://spring.io/projects/spring-framework#learn

一、个别问题

开发中次要应用 Spring 的什么技术 ?

  1. IOC 容器治理各层的组件
  2. 应用 AOP 配置申明式事务
  3. 整合其余框架

Spring 有哪些长处?

  • 轻量级:Spring 在大小和透明性方面相对属于轻量级的,根底版本的 Spring 框架大概只有 2MB。
  • 管制反转(IOC):Spring 应用管制反转技术实现了松耦合。依赖被注入到对象,而不是创立或寻找依赖对象。
  • 面向切面编程(AOP):Spring 反对面向切面编程,同时把利用的业务逻辑与零碎的服务拆散开来。
  • 容器:Spring 蕴含并管理应用程序对象的配置及生命周期。
  • MVC 框架:Spring 的 web 框架是一个设计低劣的 web MVC 框架,很好的取代了一些 web 框架。
  • 事务管理 :Spring 对下至本地业务上至全局业务(JAT) 提供了对立的事务管理接口。
  • 异样解决 :Spring 提供一个不便的 API 将特定技术的异样(由 JDBC, Hibernate, 或 JDO 抛出) 转化为统一的、Unchecked 异样。

Spring 模块

简述 AOP 和 IOC 概念

AOP:Aspect Oriented Program, 面向 (方面) 切面的编程;Filter(过滤器)也是一种 AOP. AOP 是一种新的 方法论, 是对传统 OOP(Object-OrientedProgramming, 面向对象编程) 的补充. AOP 的次要编程对象是切面(aspect), 而切面模块化横切关注点. 能够举例通过事务阐明.

IOC:Invert Of Control, 管制反转. 也称为 DI(依赖注入)其思维是反转资源获取的方向. 传统的资源查找形式要求组件向容器发动申请查找资源. 作为回应, 容器适时的返回资源. 而利用了 IOC 之后, 则是容器被动地将资源推送给它所治理的组件, 组件所要做的仅是抉择一种适合的形式来承受资源. 这种行为也被称为查找的被动模式

二、依赖注入

IoC(Inverse of Control: 管制反转)是一种 设计思维 ,就是 将本来在程序中手动创建对象的控制权,交由 Spring 框架来治理。 IoC 在其余语言中也有利用,并非 Spring 特有。IoC 容器是 Spring 用来实现 IoC 的载体,IoC 容器实际上就是个 Map(key,value),Map 中寄存的是各种对象。

将对象之间的相互依赖关系交给 IoC 容器来治理,并由 IoC 容器实现对象的注入。这样能够很大水平上简化利用的开发,把利用从简单的依赖关系中解放出来。IoC 容器就像是一个工厂一样,当咱们须要创立一个对象的时候,只须要配置好配置文件 / 注解即可,齐全不必思考对象是如何被创立进去的。 在理论我的项目中一个 Service 类可能有几百甚至上千个类作为它的底层,如果咱们须要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只须要配置好,而后在须要的中央援用就行了,这大大增加了我的项目的可维护性且升高了开发难度。

什么是 Spring IOC 容器?

Spring 框架的外围是 Spring 容器。容器创建对象,将它们拆卸在一起,配置它们并治理它们的残缺生命周期。Spring 容器应用依赖注入来治理组成应用程序的组件。容器通过读取提供的配置元数据来接管对象进行实例化,配置和组装的指令。该元数据能够通过 XML,Java 注解或 Java 代码提供。

什么是依赖注入?

依赖注入(DI,Dependency Injection)是在编译阶段尚未知所需的性能是来自哪个的类的状况下,将其余对象所依赖的性能对象实例化的模式 。这就须要一种机制用来激活相应的组件以提供特定的性能,所以 依赖注入是管制反转的根底。否则如果在组件不受框架管制的状况下,框架又怎么晓得要创立哪个组件?

依赖注入有以下三种实现形式:

  1. 结构器注入
  2. Setter 办法注入(属性注入)
  3. 接口注入

Spring 中有多少种 IOC 容器?

在 Spring IOC 容器读取 Bean 配置创立 Bean 实例之前,必须对它进行实例化。只有在容器实例化后,才能够从 IOC 容器里获取 Bean 实例并应用

Spring 提供了两种类型的 IOC 容器实现

  • BeanFactory:IOC 容器的根本实现
  • ApplicationContext:提供了更多的高级个性,是 BeanFactory 的子接口

BeanFactory 是 Spring 框架的基础设施,面向 Spring 自身;ApplicationContext 面向应用 Spring 框架的开发者,简直所有的利用场合都间接应用 ApplicationContext 而非底层的 BeanFactory;

无论应用何种形式, 配置文件是雷同的。

BeanFactory 和 ApplicationContext 区别

BeanFactory ApplicationContext
懒加载 即时加载
它应用语法显式提供资源对象 它本人创立和治理资源对象
不反对国际化 反对国际化
不反对基于依赖的注解 反对基于依赖的注解

ApplicationContext

ApplicationContext 的次要实现类:

  • ClassPathXmlApplicationContext:从类门路下加载配置文件
  • FileSystemXmlApplicationContext: 从文件系统中加载配置文件
  • ConfigurableApplicationContext 扩大于 ApplicationContext,新减少两个次要办法:refresh() 和 close(),让 ApplicationContext 具备启动、刷新和敞开上下文的能力
  • WebApplicationContext 是专门为 WEB 利用而筹备的,它容许从绝对于 WEB 根目录的门路中实现初始化工作
  • ApplicationContext 在初始化上下文时就实例化所有单例的 Bean

从 IOC 容器中获取 Bean

  • 调用 ApplicationContext 的 getBean() 办法
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
helloWorld.hello();

列举 IoC 的一些益处

  • 它将最小化应用程序中的代码量;
  • 它将使您的应用程序易于测试,因为它不须要单元测试用例中的任何单例或 JNDI 查找机制;
  • 它以最小的影响和起码的侵入机制促成松耦合;
  • 它反对即时的实例化和提早加载服务

Spring IoC 的实现机制

Spring 中的 IoC 的实现原理就是工厂模式加反射机制,示例:

interface Fruit {public abstract void eat();
}
class Apple implements Fruit {public void eat(){System.out.println("Apple");
    }
}
class Orange implements Fruit {public void eat(){System.out.println("Orange");
    }
}
class Factory {public static Fruit getInstance(String ClassName) {
        Fruit f=null;
        try {f=(Fruit)Class.forName(ClassName).newInstance();} catch (Exception e) {e.printStackTrace();
        }
        return f;
    }
}
class Client {public static void main(String[] a) {Fruit f=Factory.getInstance("priv.starfish.spring.Apple");
        if(f!=null){f.eat();
        }
    }
}

三、Beans

什么是 Spring Beans?

  • 它们是形成用户应用程序骨干的对象
  • Bean 由 Spring IoC 容器治理
  • 它们由 Spring IoC 容器实例化,配置,拆卸和治理
  • Bean 是基于用户提供给容器的配置元数据创立

Spring 提供了哪些配置形式?

  • 基于 xml 配置

    bean 所需的依赖项和服务在 XML 格局的配置文件中指定。这些配置文件通常蕴含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签结尾。例如:

    <bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
     <property name="name" value="Edureka"></property>
    </bean>
  • 基于注解配置

    您能够通过在相干的类,办法或字段申明上应用注解,将 bean 配置为组件类自身,而不是应用 XML 来形容 bean 拆卸。默认状况下,Spring 容器中未关上注解拆卸。因而,您须要在应用它之前在 Spring 配置文件中启用它。例如:

    <beans>
    <context:annotation-config/>
    <!-- bean definitions go here -->
    </beans>
  • 基于 Java API 配置

    Spring 的 Java 配置是通过应用 @Bean 和 @Configuration 来实现。

    1. @Bean 注解表演与 <bean/> 元素雷同的角色。

      1. @Configuration 类容许通过简略地调用同一个类中的其余 @Bean 办法来定义 bean 间依赖关系。

例如:

@Configuration
public class StudentConfig {
    @Bean
    public StudentBean myStudent() {return new StudentBean();
    }
}

Spring Bean 的作用域?

  • 在 Spring 中, 能够在 \<bean> 元素的 scope 属性里设置 Bean 的作用域。
  • 默认状况下,Spring 只为每个在 IOC 容器里申明的 Bean 创立惟一一个实例,整个 IOC 容器范畴内都能共享该实例:所有后续的 getBean() 调用和 Bean 援用都将返回这个惟一的 Bean 实例。该作用域被称为 singleton,它是所有 Bean 的默认作用域。

Spring 容器中的 bean 能够分为 5 个范畴。所有范畴的名称都是自阐明的,然而为了防止混同,还是让咱们来解释一下:

  1. singleton:这种 bean 范畴是默认的,这种范畴确保不论承受到多少个申请,每个容器中只有一个 bean 的实例,单例的模式由 bean factory 本身来保护。
  2. prototype:原型范畴与单例范畴相同,为每一个 bean 申请提供一个实例。
  3. request:每次 HTTP 申请都会创立一个新的 bean,该作用于仅实用于 WebApplicationContext 环境,在申请实现当前,bean 会生效并被垃圾回收器回收。
  4. Session:同一个 HTTP Session 共享一个 bean,不同的 HTTP Session 应用不同的 bean。该作用于仅实用于 WebApplicationContext 环境,在 session 过期后,bean 会随之生效。
  5. global-session:全局 session 作用域,仅仅在基于 portlet 的 web 利用中才有意义,Spring5 曾经没有了。Portlet 是可能生成语义代码 (例如:HTML) 片段的小型 Java Web 插件。它们基于 portlet 容器,能够像 servlet 一样解决 HTTP 申请。然而,与 servlet 不同,每个 portlet 都有不同的会话

全局作用域与 Servlet 中的 session 作用域成果雷同。

Spring bean 容器的生命周期是什么样的?

Spring IOC 容器能够治理 Bean 的生命周期, Spring 容许在 Bean 生命周期的特定点执行定制的工作。

Spring bean 容器的生命周期流程如下:

  1. Spring 容器依据配置中的 bean 定义实例化 bean;
  2. Spring 应用依赖注入填充所有属性,如 bean 中所定义的配置;
  3. 如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName();
  4. 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递本身的实例来调用 setBeanFactory();
  5. 与下面的相似,如果实现了其余 *.Aware接口,就调用相应的办法;
  6. 如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 办法;
  7. 如果为 bean 指定了 init 办法(<bean> 的 init-method 属性),那么将调用它;
  8. 最初,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 办法;
  9. 如果 bean 实现 DisposableBean 接口,当 spring 容器敞开时,会调用 destory();
  10. 如果为 bean 指定了 destroy 办法(<bean> 的 destroy-method 属性),那么将调用它

在 bean 初始化时会经验几个阶段,要与容器对 bean 生命周期的治理交互,能够实现 InitializingBeanDisposableBean 接口。容器对前者调用 afterPropertiesSet(),对后者调用 destroy(),以容许 bean 在初始化和销毁 bean 时执行某些操作。

官网不倡议应用这两个接口,而是倡议应用 @PostConstruct@PreDestroy,或者 XML 配置中应用 init-methoddestroy-method 属性

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {public void init() {// do some initialization work}
}

等价于

public class AnotherExampleBean implements InitializingBean {public void afterPropertiesSet() {// do some initialization work}
}

Spring Bean 生命周期回调——初始化回调和销毁回调办法

实现 Bean 初始化回调和销毁回调各有三种办法,一是实现接口办法,二是在 XML 配置,三是应用注解

  • 应用注解 @PostConstruct@PreDestroy
  • 实现 InitializingBeanDisposableBean 接口
  • XML 中配置 init-methoddestroy-method

在一个 bean 中,如果配置了多种生命周期回调机制,会依照上边从上到下的秩序调用

在 Spring 中如何配置 Bean?

Bean 的配置形式: 通过全类名(反射)、通过工厂办法(动态工厂办法 & 实例工厂办法)、FactoryBean

什么是 Spring 拆卸

当 bean 在 Spring 容器中组合在一起时,它被称为拆卸或 bean 拆卸,拆卸是创立利用对象之间协作关系的行为。Spring 容器须要晓得须要什么 bean 以及容器应该如何应用依赖注入来将 bean 绑定在一起,同时拆卸 bean。

依赖注入的实质就是拆卸,拆卸是依赖注入的具体行为。

注入是实例化的过程,将创立的 bean 放在 Spring 容器中,分为属性注入(setter 形式)、结构器注入

什么是 bean 主动拆卸?

Spring 容器能够主动配置相互协作 beans 之间的关联关系。这意味着 Spring 能够主动配置一个 bean 和其余合作 bean 之间的关系,通过查看 BeanFactory 的内容里有没有应用 < property> 元素。

在 Spring 框架中共有 5 种主动拆卸,让咱们逐个剖析

  1. no:这是 Spring 框架的默认设置,在该设置下主动拆卸是敞开的,开发者须要自行在 beanautowire 属性里指定主动拆卸的模式
  2. byName:该选项能够依据 bean 名称设置依赖关系。当向一个 bean 中主动拆卸一个属性时,容器将依据 bean 的名称主动在在配置文件中查问一个匹配的 bean。如果找到的话,就拆卸这个属性,如果没找到的话就报错。
  3. byType:该选项能够依据 bean 类型设置依赖关系。当向一个 bean 中主动拆卸一个属性时,容器将依据 bean 的类型主动在在配置文件中查问一个匹配的 bean。如果找到的话,就拆卸这个属性,如果没找到的话就报错。
  4. constructor:结构器的主动拆卸和 byType 模式相似,然而仅仅实用于与有结构器雷同参数的 bean,如果在容器中没有找到与结构器参数类型统一的 bean,那么将会抛出异样。
  5. autodetect:Spring 首先尝试通过 constructor 应用主动拆卸来连贯,如果它不执行,Spring 尝试通过 byType 来主动拆卸

主动拆卸有什么局限?

  • 根本数据类型的值、字符串字面量、类字面量无奈应用主动拆卸来注入。
  • 拆卸依赖中若是呈现匹配到多个 bean(呈现歧义性),拆卸将会失败

通过注解的形式配置 bean | 什么是基于注解的容器配置

组件扫描(component scanning): Spring 可能从 classpath 下主动扫描, 侦测和实例化具备特定注解的组件。

特定组件包含:

  • @Component:根本注解, 标识了一个受 Spring 治理的组件
  • @Respository:标识长久层组件
  • @Service:标识服务层 (业务层) 组件
  • @Controller:标识体现层组件

对于扫描到的组件,,Spring 有默认的命名策略:应用非限定类名,,第一个字母小写。也能够在注解中通过 value 属性值标识组件的名称。

当在组件类上应用了特定的注解之后,,还须要在 Spring 的配置文件中申明 <context:component-scan>

  • base-package 属性指定一个须要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类
  • 当须要扫描多个包时, 能够应用逗号分隔
  • 如果仅心愿扫描特定的类而非基包下的所有类,可应用 resource-pattern 属性过滤特定的类,示例:

    <context:component-scan base-package="priv.starfish.front.web.controller"
        annotation-config="true" resource-pattern="autowire/*.class"/>

如何在 spring 中启动注解拆卸?

默认状况下,Spring 容器中未关上注解拆卸。因而,要应用基于注解拆卸,咱们必须通过配置<context:annotation-config /> 元素在 Spring 配置文件中启用它。

四、AOP

👴:形容一下 Spring AOP 呗?

​ 你有没有⽤过 Spring 的 AOP? 是⽤来⼲嘛的? ⼤概会怎么使⽤?

什么是 AOP?

AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程) 的补充。在 OOP 中, 咱们以类 (class) 作为咱们的根本单元,而 AOP 中的根本单元是 Aspect(切面)

AOP 的次要编程对象是切面(aspect)

在利用 AOP 编程时, 依然须要定义公共性能,但能够明确的定义这个性能在哪里,,以什么形式利用,,并且不用批改受影响的类。这样一来横切关注点就被模块化到非凡的对象 (切面) 里。

AOP 的益处:

  • 每个事物逻辑位于一个地位,代码不扩散,便于保护和降级
  • 业务模块更简洁, 只蕴含外围业务代码

AOP 术语

  • 切面(Aspect):横切关注点(逾越应用程序多个模块的性能),被模块化的非凡对象
  • 连接点(Joinpoint):程序执行的某个特定地位,如类某个办法调用前、调用后、办法抛出异样后等。在这个地位咱们能够插入一个 AOP 切面,它实际上是应用程序执行 Spring AOP 的地位
  • 告诉(Advice):告诉是个在办法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。Spring 切面能够利用五种类型的告诉:

    • before:前置告诉,在一个办法执行前被调用
    • after:在办法执行之后调用的告诉,无论形式执行是否胜利
    • after-returning:仅当办法胜利实现后执行的告诉
    • after-throwing:在办法抛出异样退出时执行的告诉
    • around:在办法执行之前和之后调用的告诉
  • 指标(Target):被告诉的对象,通常是一个代理对象,也指被告诉(advice)对象
  • 代理(Proxy):向指标对象利用告诉之后创立的对象
  • 切点(pointcut):每个类都领有多个连接点,程序运行中的一些工夫点,例如一个办法的执行,或者是一个异样的解决。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查问条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行形容,它应用类和办法作为连接点的查问条件
  • 引入(Introduction):引入容许咱们向现有的类增加新办法或属性
  • 织入(Weaving):织入是把切面利用到指标对象并创立新的代理对象的过程

Spring AOP

  • AspectJ:Java 社区里最残缺最风行的 AOP 框架
  • 在 Spring2.0 以上版本中, 能够应用基于 AspectJ 注解或基于 XML 配置的 AOP

在 Spring 中启用 AspectJ 注解反对

  • 要在 Spring 利用中应用 AspectJ 注解, 必须在 classpath 下蕴含 AspectJ 类库:aopalliance.jaraspectj.weaver.jarspring-aspects.jar
  • 将 aop Schema 增加到 <beans> 根元素中.
  • 要在 Spring IOC 容器中启用 AspectJ 注解反对, 只有在 Bean 配置文件中定义一个空的 XML 元素 <aop:aspectj-autoproxy>
  • 当 Spring IOC 容器侦测到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素时, 会主动为与 AspectJ 切面匹配的 Bean 创立代理.

有哪写类型的告诉(Advice)| 用 AspectJ 注解申明切面

  • 要在 Spring 中申明 AspectJ 切面, 只须要在 IOC 容器中将切面申明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创立代理.
  • 在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类.
  • 告诉是标注有某种注解的简略的 Java 办法.
  • AspectJ 反对 5 种类型的告诉注解:

    • @Before: 前置告诉, 在办法执行之前执行
    • @After: 后置告诉, 在办法执行之后执行
    • @AfterRunning: 返回告诉, 在办法返回后果之后执行
    • @AfterThrowing: 异样告诉, 在办法抛出异样之后
    • @Around: 盘绕告诉, 围绕着办法执行

AOP 有哪些实现形式?

实现 AOP 的技术,次要分为两大类:

  • 动态代理 – 指应用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因而也称为编译时加强;

    • 编译时编织(非凡编译器实现)
    • 类加载时编织(非凡的类加载器实现)。
  • 动静代理 – 在运行时在内存中“长期”生成 AOP 动静代理类,因而也被称为运行时加强。

    • JDK 动静代理
    • CGLIB

有哪些不同的 AOP 实现

Spring AOP and AspectJ AOP 有什么区别?

  • Spring AOP 基于动静代理形式实现,AspectJ 基于动态代理形式实现。
  • Spring AOP 仅反对办法级别的 PointCut;提供了齐全的 AOP 反对,它还反对属性级别的 PointCut。

五、数据拜访

Spring 对 JDBC 的反对

JdbcTemplate 简介

  • 为了使 JDBC 更加易于应用, Spring 在 JDBC API 上定义了一个形象层, 以此建设一个 JDBC 存取框架
  • 作为 Spring JDBC 框架的外围,JDBCTemplate 的设计目标是为不同类型的 JDBC 操作提供模板办法。每个模板办法都能管制整个过程,并容许笼罩过程中的特定工作。通过这种形式,能够在尽可能保留灵活性的状况下,将数据库存取的工作量降到最低。

Spring 反对哪些 ORM 框架

Hibernate、iBatis、JPA、JDO、OJB

六、事务

Spring 中的事务管理

作为企业级应用程序框架,,Spring 在不同的事务管理 API 之上定义了一个形象层,而应用程序开发人员不用理解底层的事务管理 API,就能够应用 Spring 的事务管理机制

Spring 既反对 编程式事务管理 ,也反对 申明式的事务管理

  • 编程式事务管理:将事务管理代码嵌入到业务办法中来管制事务的提交和回滚,在编程式治理事务时,必须在每个事务操作中蕴含额定的事务管理代码,属于硬编码
  • 申明式事务管理:大多数状况下比编程式事务管理更好用。它将事务管理代码从业务办法中分离出来,以申明的形式来实现事务管理。事务管理作为一种横切关注点,能够通过 AOP 办法模块化。Spring 通过 Spring AOP 框架反对申明式事务管理,申明式事务又分为两种:

    • 基于 XML 的申明式事务
    • 基于注解的申明式事务

事务管理器

Spring 并不间接治理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给 Hibernate 或者 JTA 等长久化机制所提供的相干平台框架的事务来实现。

Spring 事务管理器的接口是 org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring 为各个平台如 JDBC、Hibernate 等都提供了对应的事务管理器,然而具体的实现就是各个平台本人的事件了。

Spring 中的事务管理器的不同实现

事务管理器以一般的 Bean 模式申明在 Spring IOC 容器中

  • 在应用程序中只须要解决一个数据源, 而且通过 JDBC 存取

    org.springframework.jdbc.datasource.DataSourceTransactionManager
  • 在 JavaEE 应用服务器上用 JTA(Java Transaction API) 进行事务管理

    org.springframework.transaction.jta.JtaTransactionManager
  • 用 Hibernate 框架存取数据库

    org.springframework.orm.hibernate3.HibernateTransactionManager

事务管理器以一般的 Bean 模式申明在 Spring IOC 容器中

用事务告诉申明式地治理事务

  • 事务管理是一种横切关注点
  • 为了在 Spring 2.x 中启用申明式事务管理,能够通过 tx Schema 中定义的 \<tx:advice> 元素申明事务告诉,为此必须当时将这个 Schema 定义增加到 \<beans> 根元素中去
  • 申明了事务告诉后,就须要将它与切入点关联起来。因为事务告诉是在 \<aop:config> 元素内部申明的, 所以它无奈间接与切入点产生关联,所以必须在 \<aop:config> 元素中申明一个增强器告诉与切入点关联起来.
  • 因为 Spring AOP 是基于代理的办法,所以只能加强公共办法。因而, 只有私有办法能力通过 Spring AOP 进行事务管理。

用 @Transactional 注解申明式地治理事务

  • 除了在带有切入点,告诉和增强器的 Bean 配置文件中申明事务外,Spring 还容许简略地用 @Transactional 注解来标注事务办法
  • 为了将办法定义为反对事务处理的,能够为办法增加 @Transactional 注解,依据 Spring AOP 基于代理机制,只能标注私有办法.
  • 能够在办法或者类级别上增加 @Transactional 注解。当把这个注解利用到类上时,这个类中的所有公共办法都会被定义成反对事务处理的
  • 在 Bean 配置文件中只须要启用 <tx:annotation-driven>元素, 并为之指定事务管理器就能够了
  • 如果事务处理器的名称是 transactionManager, 就能够在 <tx:annotation-driven> 元素中省略 transaction-manager 属性,这个元素会自动检测该名称的事务处理器

事务流传属性

  • 当事务办法被另一个事务办法调用时,必须指定事务应该如何流传。例如:办法可能持续在现有事务中运行,也可能开启一个新事务,并在本人的事务中运行
  • 事务的流传行为能够由流传属性指定,Spring 定义了 7 品种流传行为:
流传行为 意义
PROPAGATION_MANDATORY 示意该办法必须运行在一个事务中。如果以后没有事务正在产生,将抛出一个异样
PROPAGATION_NESTED 示意如果以后正有一个事务在进行中,则该办法该当运行在一个嵌套式事务中。被嵌套的事务能够独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像 PROPAGATION_REQUIRES 一样。
PROPAGATION_NEVER 示意以后的办法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异样。
PROPAGATION_NOT_SUPPORTED 示意该办法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该办法的运行期间被挂起。
PROPAGATION_SUPPORTS 示意以后办法不须要事务性上下文,然而如果有一个事务曾经在运行的话,它也能够在这个事务里运行。
PROPAGATION_REQUIRES_NEW 示意以后办法必须在它本人的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个办法运行期间被挂起。
PROPAGATION_REQUIRES 示意以后办法必须在一个事务中运行。如果一个现有事务正在进行中,该办法将在那个事务中运行,否则就要开始一个新事务。

Spring 反对的事务隔离级别

隔离级别 含意
ISOLATION_DEFAULT 应用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED 容许读取尚未提交的更改。可能导致脏读、幻影读或不可反复读。
ISOLATION_READ_COMMITTED 容许从曾经提交的并发事务读取。可避免脏读,但幻影读和不可反复读仍可能会产生。
ISOLATION_REPEATABLE_READ 对雷同字段的屡次读取的后果是统一的,除非数据被以后事务自身扭转。可避免脏读和不可反复读,但幻影读仍可能产生。
ISOLATION_SERIALIZABLE 齐全遵从 ACID 的隔离级别,确保不产生脏读、不可反复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过齐全锁定以后事务所波及的数据表来实现的。

事务的隔离级别要失去底层数据库引擎的反对,而不是应用程序或者框架的反对;

Oracle 反对的 2 种事务隔离级别,Mysql 反对 4 种事务隔离级别。

设置隔离事务属性

用 @Transactional 注解申明式地治理事务时能够在 @Transactional 的 isolation 属性中设置隔离级别

在 Spring 事务告诉中, 能够在 <tx:method> 元素中指定隔离级别

设置回滚事务属性

  • 默认状况下只有未查看异样 (RuntimeException 和 Error 类型的异样) 会导致事务回滚,而受查看异样不会。
  • 事务的回滚规定能够通过 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性来定义,这两个属性被申明为 Class[] 类型的,因而能够为这两个属性指定多个异样类。

    • rollbackFor:遇到时必须进行回滚
    • noRollbackFor:一组异样类,遇到时必须不回滚

超时和只读属性

  • 因为事务能够在行和表上取得锁,因而长事务会占用资源, 并对整体性能产生影响
  • 如果一个事物只读取数据但不做批改,数据库引擎能够对这个事务进行优化
  • 超时事务属性:事务在强制回滚之前能够放弃多久,这样能够避免长期运行的事务占用资源
  • 只读事务属性:示意这个事务只读取数据但不更新数据,这样能够帮忙数据库引擎优化事务

设置超时和只读事务属性

  • 超时和只读属性能够在 @Transactional 注解中定义,超时属性以秒为单位来计算

列出两种形式的示例:

@Transactional(propagation = Propagation.NESTED, timeout = 1000, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true" propagation="REQUIRES_NEW" isolation="READ_COMMITTED" timeout="30" no-rollback-for="java.lang.ArithmeticException"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- ensure that the above transactional advice runs for any execution
        of an operation defined by the FooService interface -->
    <aop:config>
        <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
    </aop:config>

七、MVC

Spring MVC 框架有什么用?

Spring Web MVC 框架提供 模型 - 视图 - 控制器 架构和随时可用的组件,用于开发灵便且涣散耦合的 Web 应用程序。MVC 模式有助于拆散应用程序的不同方面,如输出逻辑,业务逻辑和 UI 逻辑,同时在所有这些元素之间提供涣散耦合。

Spring MVC 的长处

  • 能够反对各种视图技术, 而不仅仅局限于 JSP
  • 与 Spring 框架集成(如 IoC 容器、AOP 等)
  • 清晰的角色调配:前端控制器(dispatcherServlet),申请到处理器映射(handlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)
  • 反对各种申请资源的映射策略

Spring MVC 的运行流程 | DispatcherServlet 形容

在整个 Spring MVC 框架中,DispatcherServlet 处于外围地位,负责协调和组织不同组件以实现申请解决并返回响应的工作

SpringMVC 解决申请过程:

  1. 若一个申请匹配 DispatcherServlet 的申请映射门路(在 web.xml 中指定),WEB 容器将该申请转交给 DispatcherServlet 解决
  2. DispatcherServlet 接管到申请后, 将依据申请信息 (包含 URL、HTTP 办法、申请头、申请参数、Cookie 等) 及 HandlerMapping 的配置找到解决申请的处理器(Handler)。可将 HandlerMapping 看成路由控制器,将 Handler 看成指标主机
  3. 当 DispatcherServlet 依据 HandlerMapping 失去对应以后申请的 Handler 后,通过 HandlerAdapter 对 Handler 进行封装,再以对立的适配器接口调用 Handler
  4. 处理器实现业务逻辑的解决后将返回一个 ModelAndView 给 DispatcherServlet,ModelAndView 蕴含了视图逻辑名和模型数据信息
  5. DispatcherServlet 借助 ViewResoler 实现逻辑视图名到实在视图对象的解析
  6. 失去实在视图对象 View 后, DispatcherServlet 应用这个 View 对 ModelAndView 中的模型数据进行视图渲染

Spring 的 Controller 是单例的吗?多线程状况下 Controller 是线程平安吗?

controller 默认是单例的,不要应用非动态的成员变量,否则会产生数据逻辑凌乱。正因为单例所以不是线程平安的

@Controller
//@Scope("prototype")
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {System.out.println(++num);
    }

}

咱们首先拜访 http://localhost:8080/testScope,失去的答案是 1
而后咱们再拜访 http://localhost:8080/testScope2,失去的答案是 2

接下来咱们再来给 controller 减少作用多例 @Scope("prototype")

咱们仍旧首先拜访 http://localhost:8080/testScope,失去的答案是 1
而后咱们再拜访 http://localhost:8080/testScope2,失去的答案还是 1

单例是不平安的,会导致属性重复使用

解决方案
  1. 不要在 controller 中定义成员变量
  2. 万一必须要定义一个非动态成员变量时候,则通过注解 @Scope(“prototype”),将其设置为多例模式。
  3. 在 Controller 中应用 ThreadLocal 变量

八、注解

什么是基于 Java 的 Spring 注解配置? 给一些注解的例子

基于 Java 的配置,容许你在大量的 Java 注解的帮忙下,进行你的大部分 Spring 配置而非通过 XML 文件。

以 @Configuration 注解为例,它用来标记类能够当做一个 bean 的定义,被 Spring IOC 容器应用。

另一个例子是 @Bean 注解,它示意此办法将要返回一个对象,作为一个 bean 注册进 Spring 利用上下文。

@Configuration
public class StudentConfig {
    @Bean
    public StudentBean myStudent() {return new StudentBean();
    }
}

怎么开启注解拆卸?

注解拆卸在默认状况下是不开启的,为了应用注解拆卸,咱们必须在 Spring 配置文件中配置 <context:annotation-config/> 元素。

Spring MVC 罕用注解:

@Controller

在 SpringMVC 中,控制器 Controller 负责解决由 DispatcherServlet 散发的申请,它把用户申请的数据通过业务解决层解决之后封装成一个 Model,而后再把该 Model 返回给对应的 View 进行展现。在 SpringMVC 中只需应用 @Controller 标记一个类是 Controller,而后应用 @RequestMapping 和 @RequestParam 等一些注解用以定义 URL 申请和 Controller 办法之间的映射,这样的 Controller 就能被外界拜访到。

@RequestMapping

RequestMapping 是一个用来解决申请地址映射的注解,可用于类或办法上

@RequestMapping

Spring Framework 4.3 之后引入的基于 HTTP 办法的变体

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping
@PathVariable

用于将申请 URL 中的模板变量映射到性能解决办法的参数上,即取出 uri 模板中的变量作为参数

@RequestParam

应用 @RequestParam 绑定申请参数值,在解决办法入参处应用 @RequestParam 能够把申请参数传递给申请办法

  • value:参数名
  • required:是否必须。默认为 true, 示意申请参数中必须蕴含对应的参数,若不存在,将抛出异样
@RequestBody

@RequestBody 表明办法参数应该绑定到 HTTP 申请体的值

@ResponseBody

@Responsebody 示意该办法的返回后果间接写入 HTTP response body 中

个别在异步获取数据时应用,在应用 @RequestMapping 后,返回值通常解析为跳转门路,加上 @Responsebody 后返回后果不会被解析为跳转门路,而是间接写入 HTTP response body 中。比方异步获取 json 数据,加上 @Responsebody 后,会间接返回 json 数据。

@Resource 和 @Autowired

@Resource 和 @Autowired 都是做 bean 的注入时应用,其实 @Resource 并不是 Spring 的注解,它的包是 javax.annotation.Resource,须要导入,然而 Spring 反对该注解的注入。

  • 共同点:两者都能够写在字段和 setter 办法上。两者如果都写在字段上,那么就不须要再写 setter 办法。
  • 不同点

    • @Autowired 为 Spring 提供的注解,@Autowired 注解是依照类型(byType)拆卸依赖对象,默认状况下它要求依赖对象必须存在,如果容许 null 值,能够设置它的 required 属性为 false。如果咱们想应用依照名称(byName)来拆卸,能够联合 @Qualifier 注解一起应用
    • @Resource 默认依照 ByName 主动注入,由 J2EE 提供,须要导入包 javax.annotation.Resource。@Resource 有两个重要的属性:name 和 type,而 Spring 将 @ Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。所以,如果应用 name 属性,则应用 byName 的主动注入策略,而应用 type 属性时则应用 byType 主动注入策略。如果既不制订 name 也不制订 type 属性,这时将通过反射机制应用 byName 主动注入策略。
@ModelAttribute

办法入参标注该注解后, 入参的对象就会放到数据模型中

@SessionAttribute

将模型中的某个属性暂存到 HttpSession 中,以便多个申请之间能够共享这个属性

@CookieValue

@CookieValue 可让解决办法入参绑定某个 Cookie 值

@RequestHeader

申请头蕴含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将申请头中的属性值绑定到解决办法的入参中

@Component, @Controller, @Repository, @Service 有何区别?

  • @Component:将 java 类标记为 bean。它是任何 Spring 治理组件的通用构造型。Spring 的组件扫描机制能够将其拾取并将其拉入应用程序环境中
  • @Controller:将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会主动导入到 IoC 容器中
  • @Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其余行为。你能够在服务层类中应用 @Service 而不是 @Component,因为它以更好的形式指定了用意
  • @Repository:这个注解是具备相似用处和性能的 @Component 注解的特化。它为 DAO 提供了额定的益处。它将 DAO 导入 IoC 容器,并使未经查看的异样有资格转换为 Spring DataAccessException。

@Required 注解有什么作用

这个注解表明 bean 的属性必须在配置的时候设置,通过一个 bean 定义的显式的属性值或通过主动拆卸,若 @Required 注解的 bean 属性未被设置,容器将抛出 BeanInitializationException。示例:

public class Employee {
    private String name;
    @Required
    public void setName(String name){this.name=name;}
    public string getName(){return name;}
}

@Autowired 注解有什么作用

@Autowired 默认是依照类型拆卸注入的,默认状况下它要求依赖对象必须存在(能够设置它 required 属性为 false)。@Autowired 注解提供了更细粒度的管制,包含在何处以及如何实现主动拆卸。它的用法和 @Required 一样,润饰 setter 办法、结构器、属性或者具备任意名称和 / 或多个参数的 PN 办法。

public class Employee {
    private String name;
    @Autowired
    public void setName(String name) {this.name=name;}
    public string getName(){return name;}
}

@Autowired 和 @Resource 之间的区别

用处:做 bean 的注入时应用

  • @Autowired,属于 Spring 的注解,org.springframework.beans.factory.annotation.Autowired
  • @Resource,不属于 Spring 的注解,JDK1.6 反对的注解,javax.annotation.Resource

共同点:都用来拆卸 bean。写在字段上,或写在 setter 办法

不同点:@Autowired 默认按类型拆卸。依赖对象必须存在,如果要容许 null 值,能够设置它的 required 属性为 false @Autowired(required=false),也能够应用名称拆卸,配合 @Qualifier 注解

@Resource 默认是依照名称来拆卸注入的,只有当找不到与名称匹配的 bean 才会依照类型来拆卸注入

@Qualifier 注解有什么作用

当创立多个雷同类型的 bean 并心愿仅应用属性拆卸其中一个 bean 时,能够应用 @Qualifier 注解和 @Autowired 通过指定应该拆卸哪个确切的 bean 来打消歧义。

@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 申请办法映射到将解决相应申请的控制器中的特定类 / 办法。此正文可利用于两个级别:

  • 类级别:映射申请的 URL
  • 办法级别:映射 URL 以及 HTTP 申请办法

九、其余问题

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

  • 工厂设计模式 : Spring 应用工厂模式通过 BeanFactoryApplicationContext 创立 bean 对象。
  • 代理设计模式 : Spring AOP 性能的实现。
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 模板办法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就应用到了模板模式。
  • 包装器设计模式 : 咱们的我的项目须要连贯多个数据库,而且不同的客户在每次拜访中依据须要会去拜访不同的数据库。这种模式让咱们能够依据客户的需要可能动静切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个利用。
  • 适配器模式 :Spring AOP 的加强或告诉(Advice) 应用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

参考与起源

https://www.edureka.co/blog/interview-questions/spring-interv…

https://crossoverjie.top/2018/07/29/java-senior/ThreadPool/

本文由 mdnice 多平台公布

正文完
 0