面试准备:Spring/Spring MVC常见面试题汇总

文章目录

  • 1.Spring框架有什么优点?
  • 2.什么是AOP?
  • 3. 实现AOP的方式(AOP织入的三种时期)?Spring AOP是怎么实现的?
  • 4.JDK动态代理实现方式?
  • 5.PageHelper实现方式?*
  • 6.什么是IoC?什么是DI?
  • 7.Springboot自动装配实现原理?
  • 8.spring有哪些主要模块?*
  • 9.spring的Bean为什么不保证是线程安全的?如何解决?
  • 10.spring支持几种bean的作用域?
  • 11.说说自己对于 Spring MVC 的了解?spring mvc运行流程?
  • 12.@RequestMapping的作用是什么?@Autowired的作用是什么?*
  • 13.@RestController vs @Controller?@Component 和 @Bean 的区别是什么?*
  • 14.什么是SpringBoot?为什么要用?
  • 15.SpringBoot核心配置文件是什么?*
  • 16.介绍一下@SpringBootApplication注解
  • 17.什么是Spring的内部bean?*
  • 18.描述Spring框架中bean的生命周期?*
  • 19.spring中如何注入数组/集合?*
  • 20.Spring中有哪几种方法获取HttpSession对象?
  • 21.ApplicationContext有哪几种实现方式?*
  • 22.Spring里面用了哪些设计模式?
  • 23.列举几种spring的自动装配方式?*
  • 24.Spring的初始化过程?
  • 25.如何理解理解Spring容器、BeanFactory和ApplicationContext?
  • 26.Spring中的事务传播级别
  • 27.Spring的@Transactional如何实现的?
  • 28. 将一个类声明为Spring的 bean 的注解有哪些?*
  • 29. Spring 管理事务的方式有几种?*
  • 30. Spring 事务中的隔离级别有哪几种?*
  • 31. 如何使用JPA在数据库中非持久化一个字段?*
  • 32. 如何读取配置文件信息?*
  • 33. 过滤器和拦截器的区别?如何实现?

1.Spring框架有什么优点?

  1. 轻量:低侵入式设计,代码污染极低
  2. Spring的DI机制和容器实现了对象的管理和装配,提高了组件之间的解耦,方便集成,通过配置和简单的对象注入即可集成其他框架,如 Mybatis、Hibernate、Shiro…
  3. Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用
  4. Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
  5. Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部

2.什么是AOP?

AOP:Aspect Oriented Programming,面向切面编程。
"切面"就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,利于可操作性和可维护性。

3. 实现AOP的方式(AOP织入的三种时期)?Spring AOP是怎么实现的?

  • 静态AOP:

在编译期,切面直接以字节码的形式编译到目标字节码文件中。 在编译的时候将AOP逻辑织入到代码中,需要专有的编译器和织入器。

优点:被织入的类性能不受影响。
缺点:不够灵活

  • 动态AOP(JDK动态代理):

JDK动态代理是实际上使用代理模式,在运行期动态生成目标类的代理类,然后在代理方法内部完成代理逻辑,通过代理类做请发转发。

优点:Java标准库原生支持,使用简单,无需引用额外的包。相对于静态AOP更灵活。
缺点:带代理的类必须是接口,灵活性受到一些限制;使用反射会影响一些性能。

  • 动态代码字节生成(CGLib):

在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。
CGLib是动态代码字节生成的实现,它封装字节码生成工具Asm,原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP 不需要基于接口
CGLIB动态代理主要用到拦截方法的技术,主要涉及的类:Enhancer和MethodInceptor接口

优点:没有接口也可以织入,灵活性高。
缺点:扩展类的实例方法为final时,则无法进行织入


Spring AOP 中的代理使用逻辑:

  • 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP;
  • 如果目标对象没有实现接口,则采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 动态代理之间转换。

AspectJ AOP使用的则是编译时增强,Spring AOP 属于运行时增强。

4.JDK动态代理实现方式?

JDK动态代理是实际上使用代理模式,在运行期动态生成目标类的代理类,然后在代理类中完成织入逻辑。
主要实现方式依赖java.lang.reflect包下的InvocationHandler和Proxy类。 通过实现InvocationHandler来接口创建代理方法,在方法内部实现代理逻辑,并且使用代理类转发请求给目标类。代理类是通过Proxy的静态方法反射生成的,它通过传入相应的类加载器、接口以及目标类的实现,来反射创建代理类。
但是由于Proxy静态方法生成的代理类会有一个共同的父类Proxy,Java又无法实现多继承,所以只能通过接口来完成动态代理。

参考:Java设计模式——代理模式
参考:Proxy类的实现方式。

5.PageHelper实现方式?*

参考结合源码理解PageHelper。

6.什么是IoC?什么是DI?

Java架构直通车——彻底了解DIP、IOC与DI之间的关系

7.Springboot自动装配实现原理?

过程参考:Java架构直通车——@SpringApplication自动装配原理。

原理参考:工厂模式加反射机制。

8.spring有哪些主要模块?*

Spring框架的七大模块

1.Spring Core
框架的最基础部分,提供 IoC 容器,对 bean 进行管理。

2.Spring Context
基于 bean,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化、校验和调度等功能。

3.Spring DAO
提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码,还提供了声明性事务管理方法。

4.Spring ORM
提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate、MyBatis 等。

5.Spring AOP
提供了符合AOP Alliance规范的面向方面的编程实现。

6.Spring Web
提供了基础的 Web 开发的上下文信息,可与其他 web 进行集成。

7.Spring Web MVC
提供了 Web 应用的 Model-View-Controller 全功能实现。

9.spring的Bean为什么不保证是线程安全的?如何解决?

Spring 不保证 bean 的线程安全。
默认 spring 容器中的 bean 是单例的。当单例中存在竞态条件,即有线程安全问题。

常见的有两种解决办法:

  1. 在Bean对象中尽量避免定义可变的成员变量(无状态bean)。
  2. 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

10.spring支持几种bean的作用域?

  • singleton:单例模式,在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例
  • prototype:原型模式,每次通过容器的getbean方法获取 prototype 定义的 bean 时(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法),都产生一个新的 bean 实例

只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效

  • request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
  • session:同一个 Session 共享一个 bean 实例。
  • global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。

什么时候使用prototype,什么时候使用singleton,主要看是看bean是有状态bean还是无状态bean:

有状态bean,如果配置为singleton,会出现线程安全问题,比如下面的代码:

package com.test;    
public class TestServiceImpl implements TestService{  
   private User user;
   public void test1(User u) throws Exception {  
       this.user = u;                          //1  
       test2();  
   }  
   
   public void test2() throws Exception {  
       System.out.println(user.getId());       //2 
   }     
}

如果该Bean配置为singleton,在并发访问下如果某一个线程修改了user的值,那么另外的线程可能会出错的。
实际应该是这个例子不应该用实例变量,这样就使得这个Bean由无状态变成了有状态Bean。
如果用有状态的bean,就要用prototype模式,每次在注入的时候就重新创建一个bean,在多线程中互不影响。

11.说说自己对于 Spring MVC 的了解?spring mvc运行流程?

spring MVC是一种分层设计思想,达到解耦合的目的。MVC主要是Model View和Controller,他的运行流程是:…

参考:DispatchServlet处理流程
参考:Rest处理流程

12.@RequestMapping的作用是什么?@Autowired的作用是什么?*

@RequestMapping 是一个注解,用来标识 http 请求地址与 Controller 类的方法之间的映射。

@Autowired 是一个注解,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。

13.@RestController vs @Controller?@Component 和 @Bean 的区别是什么?*

单独使用 @Controller 不加 @ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的Spring MVC 的应用,对应于前后端不分离的情况。

@RestController只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离)。


  1. 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
  2. @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
  3. @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

14.什么是SpringBoot?为什么要用?

spring boot 目的就是为了简化开发,它能够使得编码和配置变得简单,避免了一些重复的编码和配置,减少开发的代码量。另外,在SpringMVC的时候需要去手动配置Tomcat,或者通过打war包放到tomcat下运行个。而SpringBoot可以直接通过maven依赖引入tomcat或者jetty,通过打jar包再使用java -jar命令运行,简化部署。另外,监控也变得简单。

简而言之,好处:

  • 编码变得简单
  • 配置变得简单
  • 部署变得简单
  • 监控变得简单

15.SpringBoot核心配置文件是什么?*

Spring Boot 有两种类型的配置文件,application 和 bootstrap 文件
Spring Boot会自动加载classpath目前下的这两个文件,文件格式为 properties 或 yml 格式

*.properties 文件是 key=value 的形式
*.yml 是 key: value 的形式
*.yml 加载的属性是有顺序的,但不支持 @PropertySource 注解来导入配置,一般推荐用yml文件,看下来更加形象

bootstrap 配置文件是系统级别的,用来加载外部配置,如配置中心的配置信息,也可以用来定义系统不会变化的属性.bootstatp 文件的加载先于application文件
application 配置文件是应用级别的,是当前应用的配置文件

16.介绍一下@SpringBootApplication注解

package org.springframework.boot.autoconfigure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
   ......
}
package org.springframework.boot;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

可以看出大概可以把 @SpringBootApplication 看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @ComponentScan: 扫描被@Component (@Service,@Controller)注解的bean,注解默认会扫描该类所在的包下所有的类。
  • @Configuration:允许在上下文中注册额外的bean或导入其他配置类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

注意这一句@Import({AutoConfigurationImportSelector.class}),通过Spring 提供的 @Import 注解导入了AutoConfigurationImportSelector类(@Import 注解可以导入配置类或者Bean到当前类中),AutoConfigurationImportSelector类中getCandidateConfigurations方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理。

17.什么是Spring的内部bean?*

当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,内部bean通常是匿名的,它们的Scope一般是prototype。

如:

	  
    <bean id="d1" class="com.yang.Dog">  
        <property name="name" value="lala">property>  
        <property name="age" value="9">property>  
        <property name="style" value="Hashiqi">property>  
    bean>  
      
    <bean id="d2" class="com.yang.person">  
        <constructor-arg index="0" value="andreny">constructor-arg>  
        <constructor-arg index="1" value="15454">constructor-arg>  
        <constructor-arg index="2" value="teacher">constructor-arg>  
    bean>  
    
    <bean id="m1" class="com.yang.myshow">  
        
        <property name="dog" ref="d1">property>  
        
        <property name="p" ref="d2">property>  
    bean>  

18.描述Spring框架中bean的生命周期?*

1、Spring容器 从XML 文件中读取bean的定义,并实例化bean。
2、Spring根据bean的定义填充所有的属性。
3、如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
4、如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
5、如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
6、如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
7、如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
8、如果bean实现了 DisposableBean,它将调用destroy()方法。
面试准备:Spring/Spring MVC常见面试题汇总_第1张图片

19.spring中如何注入数组/集合?*

Spring提供以下几种集合的配置元素:
类型用于注入一列值,允许有相同的值。
类型用于注入一组值,不允许有相同的值。
类型用于注入一组键值对,键和值都可以为任意类型。
类型用于注入一组键值对,键和值都只能为String类型。

<beans>
  <bean id="at" class="test.array.ArrayTest">
    <property name="names">
      <list>
        <value>aaavalue>
        <value>bbbvalue>
      list>
    property>
  bean>
beans>

也可以通过注解的方式注入:

public interface InjectService extends InitializingBean{
    public void inject();
}

@Service
public class InjectServiceImpl implements InjectService {@Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("begin class:" + this);
    }@Override
    public void inject() {
        System.out.println("this is inject service");
    }
}

@Controller
public class InjectController {@Autowired
    private List<InjectService> list;
    @Autowired
    private Map<String, InjectService> map;
    @Autowired
    private Set<InjectService> set;@RequestMapping("inject.html")
    public void injectUrl() {
        for (InjectService service : list) {
            System.out.println("inject list service class:" + service);
        }
        for (String key : map.keySet()) {
            System.out.println("inject map service class:" + map.get(key));
        }
        for (InjectService service : set) {
            System.out.println("inject map service class:" + service);
        }
    }
}

对于list、set填入的是注入类型Spring管理的实例,对于map,Spring会将service的名字作为key,对象作为value封装进入Map。

20.Spring中有哪几种方法获取HttpSession对象?

	@RequestMapping("/session")
    public Map test(HttpSession session, String otherParam) {
        ...
    }

或者

    @RequestMapping("/session")
    public String setSession(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        ...
   }

21.ApplicationContext有哪几种实现方式?*

有以下3种实现方式:

1、FileSystemXmlApplicationContext :从文件系统加载IoC配置文件
2、ClassPathXmlApplicationContext:从文件系统加载IoC配置文件
3、WebXmlApplicationContext:通过WebApplicationContextUtils获取

        //加载单个xml文件
        ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
        //加载多个xml文件
        String[] locations = new String[]{"bean1.xml", "bean2.xml", "bean3.xml"};
        ctx = new FileSystemXmlApplicationContext(locations);
 
        //加载单个xml文件
        ctx = new ClassPathXmlApplicationContext("bean.xml");
        //加载多个xml文件
        locations = new String[]{"bean1.xml", "bean2.xml", "bean3.xml"};
        ctx = new ClassPathXmlApplicationContext(locations);
 
        
        ServletContext servletContext = request.getSession().getServletContext();
        ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

22.Spring里面用了哪些设计模式?

工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。

详情参考:Spring用了哪些模式

23.列举几种spring的自动装配方式?*

有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
(1)no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
(2)byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
(3)byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
(4)constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
(5)autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。

24.Spring的初始化过程?

参考:Java架构直通车——SpringApplication的初始化过程

25.如何理解理解Spring容器、BeanFactory和ApplicationContext?

spring容器可以理解为对于对象的管理和装配的地方,它负责了对象的整个生命周期–创建、装配、销毁。而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器。

BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。

BeanFactory和ApplicationContext之间的关系:

  1. BeanFactory。
    这是最简单的容器,只能提供基本的DI功能和对象生命周期的管理,所以不太常用。
  2. ApplicationContext
    继承自BeanFactory,它能提供更多企业级的服务,比如AOP,事件监听机制等。

另外,BeanFactory使用的是懒加载。而ApplicationContext默认是初始化的时候加载所有的Singleton Bean,在系统创建前期会有较大的系统开销,之后性能会有较好的改善。

26.Spring中的事务传播级别

1)@Transactional(propagation=Propagation.REQUIRED):默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行,所以这个级别通常能满足处理大多数的业务场景。

2)@Transactional(propagation=PROPAGATION.SUPPORTS):从字面意思就知道,supports(支持),该传播级别的特点是,如果上下文存在事务,则支持当前事务,加入到事务执行,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作,应用场景较少。

3)@Transactional(propagation=PROPAGATION.MANDATORY):该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。

4)@Transactional(propagation=PROPAGATION.REQUIRES_NEW):从字面即可知道,每次都要一个新的事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,当新建事务执行完成以后,上下文事务再恢复执行。

这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION.REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。

5)@Transactional(propagation=PROPAGATION.NOT_SUPPORTED) :这个也可以从字面得知,not supported(不支持),当前级别的特点是,如果上下文中存在事务,
则挂起事务,执行当前逻辑,结束后恢复上下文的事务。

这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了,用当前级别的事务模板抱起来就可以了。

6)@Transactional(propagation=PROPAGATION.NEVER):该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!

7)@Transactional(propagation=PROPAGATION.NESTED):字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。

PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将取得一个 savepoint。如果这个嵌套事务失败, 我们将回滚到此 savepoint。嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.;外部事务发生错误,嵌套事务会一并回滚。

27.Spring的@Transactional如何实现的?

实现@Transactional原理是基于spring aop的。

  1. 自动提交
    默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。
    事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。这点,Spring会在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中将底层连接的自动提交特性设置为false
// switch to manual commit if necessary。 this is very expensive in some jdbc drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already)。if (con。getautocommit()) 
{
    txobject.setmustrestoreautocommit(true);
    if (logger.isdebugenabled()) 
    {
        logger.debug("switching jdbc connection [" + con + "] to manual commit");
    }
    //首先将自动提交属性改为false
    con.setautocommit(false);
}
  1. spring事务回滚规则
    Spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。Spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
    默认配置下,Spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚)。而抛出checked异常则不会导致事务回滚。
    Spring也支持明确的配置在抛出哪些异常时回滚事务,包括checked异常。也可以明确定义哪些异常抛出时不回滚事务。
    还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

Spring AOP 自调用问题

若同一类中的其他没有 @Transactional 注解的方法内部调用有 @Transactional 注解的方法,有@Transactional 注解的方法的事务会失效。

这是由于Spring AOP代理的原因造成的,因为只有当 @Transactional 注解的方法在类以外被调用的时候,Spring 事务管理才生效。

28. 将一个类声明为Spring的 bean 的注解有哪些?*

我们一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:

@Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
@Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

29. Spring 管理事务的方式有几种?*

  • 编程式事务,在代码中硬编码。(不推荐使用)
  • 声明式事务,在配置文件中配置(推荐使用)

声明式事务又分为两种:

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

30. Spring 事务中的隔离级别有哪几种?*

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

31. 如何使用JPA在数据库中非持久化一个字段?*

下面的方式都可以不被持久化。

static String transient1; // not persistent because of static
final String transient2 =Satish; // not persistent because of final
transient String transient3; // not persistent because of transient
@Transient
String transient4; // not persistent because of @Transient

32. 如何读取配置文件信息?*

  1. 使用@value简单配置
  2. 通过@ConfigurationProperties读取
  3. @PropertySource读取指定 properties 文件

详情参考Spring 如何优雅读取配置文件?

33. 过滤器和拦截器的区别?如何实现?

参考:Java架构直通车——过滤器与拦截器使用

你可能感兴趣的:(面试准备)