Java教程

Java面试题超详细整理《Spring篇》,mybatis详细教程

本文主要是介绍Java面试题超详细整理《Spring篇》,mybatis详细教程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Spring AOP是基于动态代理实现的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理。

Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。


Spring 常用注解


将一个类声明为Spring的 bean :

  • @Controller:用来标注控制层组件,通过Controller注解标记的类就是一个SpringMVC对象,分发处理器会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解,可以把Request请求header部分的值绑定到方法的参数上。
  • @RestController:相当于Controller注解与ResponseBody的组合效果
  • @Component:通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用
  • @Reponsitory:用来标注Dao层,在daoImpl类上注释
  • @Service:用来标注业务层

其他常用注解:

  • @ResponseBody:异步请求,该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入Response对象的body区,返回的值不是html页面,而是其他某种格式的数据时使用。
  • @RequestMapping:一个用来处理请求地址映射的注解,可以作用与类上或方法上,作用于类上标表示类的所有响应请求的方法都是以该地址作为父路径。
  • @Autowired:可以对类成员变量、方法以及构造函数进行标注,完成自动装配的工作。通过该注解来消除get、set方法。
  • @PathVariable:用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出url中的变量作为参数
  • @RequestParam:主要用于在SpringMVC控制层获取参数,类似于request.getParameter(“name”);
  • @ModelAttribute:该Controller的所有方法在调用前,限制性此方法,可用于注解和方法参数中,可以把这个ModelAttribute特性,应用在BaseController中,所有的Controller继承BaseCotroller,即可实现在调用Controller时,先执行@ModelAttribute方法。

@RestController与@Controller的区别是什么?


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

在这里插入图片描述

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

在这里插入图片描述

@ResponseBody 注解的作用是将 Controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到HTTP 响应(Response)对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。


@RequestMapping注解的属性


RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping注解有六个属性:

  • value: 指定请求的实际地址,指定的地址可以是URI Template 模式;

  • method: 指定请求的method类型, GET、POST、PUT、DELETE等;

  • consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json,text/html;

  • produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

  • params: 指定request中必须包含某些参数值是,才让该方法处理。

  • headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求


@Component 和 @Bean 的区别是什么?


  • 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。

  • @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。

  • @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

@Configuration

public class AppConfig {

@Bean

public TransferService transferService() {

return new TransferServiceImpl();

}

}

//上面的代码相当于下面的 xml 配置


@PathVariable和@RequestParam的区别


  • 请求路径上有个id的变量值,可以通过@PathVariable来获取 @RequestMapping(value =“/page/{id}”, method = RequestMethod.GET)

  • @RequestParam用来获得静态的URL请求入参 spring注解时action里用到。


@Autowired和@Resource之间的区别


  • @Autowired可用于:构造函数、成员变量、Setter方法,@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

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


Bean Factory和 Application Context有什么区别?


Applicationcontext是 Beanfactory的子接口,ApplicationContext提供了更完整的功能:

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

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

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

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

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

加载方式:

  • Bean Factroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时调用 getbean(),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的 Spring的配置问题。如果Bean的某一个属性没有注入, Beanfacotry加载后,直至第一次使用调用 getbean方法才会抛出异常。
  • Applicationcontext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现 spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 Applicationcontext启动后预载入所有的单实例Bean,通过预载入单实例bean,确保当你需要的时候,不需要等待,直接使用。

创建方式:

Bean Factory通常以编程的方式被创建, Applicationcontext还能以声明的方式创建,如使用ContextLoader。

注册方式:

Bean Factory和 Application Context,都支持 Bean Postprocessor、 Beanfactory Postprocessor的使用,但两者之间的区别是: Beanfactory需要手动注册,而 Applicationcontext则是自动注册。

**相对于基本的 Beanfactory, Applicationcontext唯的不足是占用内存空间。当应用程序配置Be

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

an较多时,程序启动较慢。**


ApplicationContext通常的实现是什么?


  • FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。

  • ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。

  • WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean


Spring 中的 bean 生命周期?


解析类-》加载对象-》依赖注入-》回调Aware方法-》后置处理器处理(初始化及初始化前后)-》使用-》销毁

  • Bean 容器解析类得到配置文件中 Spring Bean 的定义(BeanDefinition)。(解析)

  • Bean 容器利用 Java Reflection API 创建一个Bean的实例。(加载对象)

  • 如果涉及到一些属性值(加了@Autowride注解的属性)利用 set()方法给对象设置属性。(依赖注入)

  • 回调Aware方法:如果实现了其他 *.Aware接口,就调用相应的方法。(回调Aware方法)

①如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。

②如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。

  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor对象,执行postProcessBeforeInitialization() 方法。(后置处理器初始化前方法)

  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。(初始化方法)

  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。

  • 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。(后置处理器初始化后方法,会进行AOP)

  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。

  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

图示:

在这里插入图片描述

后置处理器BeanPostProcessor :在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。后置处理器分为 Bean Factory后置处理器(视线了Spring的扫描)和Bean后置处理器(实现了@ Autowired注解的属性自动赋值、AOP)

bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解


Spring 中的 bean 的作用域有哪些?


  • singleton(单例模式,默认) : 每个容器中只有一个bean的实例,单例的模式由 Beanfactory自身来维护。该对象的生命周期是与 Spring IOC容器一致的(但在第一次被注入时才会创建)。

  • prototype (原型模式): 每次请求都会创建一个新的 bean 实例。在每次注入时都会创建个新的对象

  • request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session:每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

  • application:bean被定义为在 Servletcontext的生命周期中复用一个单例对象(可以实现跨容器)

  • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。


Spring 中的单例 bean 线程安全吗?


存在安全问题的。Spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理,当多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题。

但是大多数bean都是无状态的(不具有数据存储功能),比如说controller、 service和dao层,我们一般只是调用里面的方法,多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。但是dao层会操作数据库 Connection, Connection是带有状态的,比如说数据库事务, Spring的事务管理器,需要我们进行处理。

因此,不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,可以参考一下方案:

  • 使用 Threadloca把变量变为线程私有的,比如在dao层,可以使用Threadlocal为不同线程维护了一套独立的 connection副本,保证线程之间不会互相影响。

  • 改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。

  • 如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用 synchronized、OCK、CAS等这些实现线程同步的方法了。


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


  • 工厂设计模式: 由一个工厂类根据传入的参数,动态决定创建那个产品类。Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建bean 对象。

  • 单例设计模式 : 保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring 中的 Bean 默认都是单例的。

  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式(HandlerAdapter)适配Controller,对应的每一种Controller都有一种对应的适配器实现类。

  • 代理设计模式 : Spring AOP 功能的实现。AOP把切面应用到对象并创建新的代理对象。

  • 观察者模式:Spring的事件驱动模型使用的是观察着模式,Spring中Observer模式常用的地方是Listener的实现

  • 策略模式:Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource的接口来访问底层资源。

  • 装饰器模式:动态地给一个对象添加额外的职责。Spring中类名包括Wrapper或Decorator使用了装饰器模式。

  • 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。


Spring事务的实现方式


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

  • 编程式事务,在代码中硬编码。(不推荐使用)

  • 声明式事务,在配置文件中配置(推荐使用)

声明式事务又分为:

  • 基于XML的声明式事务

  • 基于注解的声明式事务

说一下 Spring的事务机制

  • spring事务底层是基于数据库事务和AOP机制的(事务这个概念是数据库层面的, Spring只是基于数据库中的事务进行了扩展)

  • 首先对于使用了@Transactional注解的bean,Spring会创建一个代理对象作为Bean

  • 当调用代理对象的方法时,会先判断该方法上是否加了@ Transactional注解

  • 如果加了,那么则利用事务管理器创建一个数据库连接,并把事务的自动提交设置为 false,然后再去执行原本的业务逻辑方法(sql)。

  • 如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交

  • 如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚

  • 针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的 rollbackfor属性进行配置,默认情况下会对 Runtimeexception和Error进行回滚。

  • Spring事务的隔离级别对应的就是数据库的隔离级别

  • Spring事务的传播机制是 Spring事务自己实现的,也是 Spring事务中最复杂的

  • Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql


@Transactional注解了解吗?


Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。

当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

@Transactional(rollbackFor = Exception.class):

在@Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。


spring事务什么时候会失效?


spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了。常见情况有如下几种:@Transactional标识的方法只有被代理对象调用时,注解才会生效

  • 发生自调用,类里面使用this调用本类的方法,此时这个this对象不是代理类,而是Userservice对象本身(解决方法很简单,让那个this变成 Euserservice的代理类即可)

  • 方法不是public的,Transactional只能用于public的方法上,否则事务不会失效,如果要用在非public方法上,可以开启( Aspectj代理模式)。

  • 异常被吃掉,事务不会回滚或者抛出的异常没有被定义,默认为 RuntimeException。


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


spring事务隔离级别就是数据库的隔离级别:外加一个默认级别

  • isolation_default(默认级别):使用后端数据库默认的隔离级别

  • read_uncommitted(读未提交读):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  • read_committed(读以提交、不可重复读):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

  • repeatable_read(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

  • serializable(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

数据库的配置隔离级别是 Read Commited,而 Spring配置的隔离级别是 Repeatable Read,请问这时隔离级别是以哪个为准?

以 Spring配置的为准,如果 spring设置的隔离级别数据库不支持,效果取决于数据库


Spring 事务中哪几种事务传播行为?


多个事务方法相互调用时事务如何在这些方法间传播:

方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。

  • REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务

  • SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行

  • MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则拋出异常

  • REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务

  • NOT_SUPPORTED:以非事务方式执行如果当前存在事务,则挂起当前事务

  • NEVER:不使用事务,如果当前事务存在,则抛出异常

  • NESTED:如果当前事务存在,则在嵌套事务中执行,否则 REQUIRED的操作一样(开启一个事务)

NESTED和 REQUIRES_NEW的区别:

REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而 NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在 NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务

NESTED和 REQUIRED的区别:

REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否 catch其异常,事务都会回滚而在 NESTED情况下,被调用方发生异常时,调用方可以 catch其异常,这样只有子事务回滚,父事务不受影响。


什么是bean的自动装配?自动装配有哪些方式?


在Spring框架中,在配置文件中设定了bean的依赖关系,Spring 容器能够自动装配相互合作的bean。这意味着容器不需要配置,能通过Bean工厂自动处理bean之间的协作,Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。

使用@Autowired注解自动装配的过程:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

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

这篇关于Java面试题超详细整理《Spring篇》,mybatis详细教程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!