【3】Spring面试总结

273 阅读14分钟

为什么要使用 spring?

  • 为了降低开发的复杂性,主要就是一个非侵入性的编程和依赖注入。
  • 简化Java开发,主要使用依赖注入和面向切面编程。

列举一些重要的Spring模块?

  • Spring Core:基础,可以说Spring其他所有的功能都依赖于该类库。主要提供IOC和DI功能。
  • Spring Aspects:该模块为与AspectJ的集成提供支持。
  • Spring AOP:提供面向切面的编程实现。
  • Spring JDBC:Java数据库连接。
  • Spring JMS:Java消息服务。
  • Spring ORM:用于支持Hibernate等ORM工具。
  • Spring Web:为创建Web应用程序提供支持。
  • Spring Test:提供了对JUnit和TestNG测试的支持。

解释一下什么是 ioc?

IOC:控制反转

  • 控制:在java中指的是对象的控制权限(创建、销毁)
  • 反转:指的是对象控制权由原来开发者在类中手动控制 反转到由Spring容器控制。

IOC(Inversion Of Controll,控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

Spring 中的 IoC 的实现原理就是工厂模式加反射机制。

BeanFactory与FactoryBean

BeanFactory是个Factory,也就是IOC容器或对象⼯⼚,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进⾏管理的。但对FactoryBean⽽⾔,通过名字看,我们可以猜出它是Bean,这个Bean不是简单的Bean,⽽是⼀个能⽣产对象的⼯⼚Bean。

BeanFactory

BeanFactory是Spring容器的顶级接⼝,给具体的IOC容器的实现提供了规范。如XmlBeanFactory、ApplicationContext等。

BeanFactory和ApplicationContext

BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在⼀般使⽤ApplicationnContext,其不但包含了BeanFactory的作⽤,同时还进⾏更多的扩展。

获取实例的时间不同

  • BeanFactory在第一次调用getBean()方法时,创建指定对象的实例。
  • ApplicationContext在spring容器启动时,加载并创建所有对象的实例

FactoryBean

是一个特殊的Bean,它可以向容器中注册两个Bean,一个是它本身,一个是FactoryBean.getObject()方法返回值所代表的Bean。

  • 将对象放入getObject()里面返回,就可以直接从容器中获取到这个对象bean,applicationContext.getBean("customerFactoryBean")
  • 如果我们想通过beanName去获取CustomerFactoryBean的单例对象,需要在beanName前面添加一个&符号,如下代码,这样就能根据beanName获取到原生对象了。
CustomerFactoryBean rawBean = (CustomerFactoryBean) applicationContext.getBean("&customerFactoryBean");

ApplicationContext是什么?通常的实现是什么?

先说BeanFactory,BeanFactory是最顶层的容器,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为  “低级容器”

ApplicationContext可以称之为  “高级容器” ,从BeanFactory继承下来,比 BeanFactory 多了更多的功能。他继承了多个接口。

通常的实现:

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

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

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

什么是依赖注入?

是指程序运行过程中,如果需要创建一个对象,无须再代码中new创建,而是依赖外部的注入。 依赖注入(DI)是控制反转(Ioc)的一种方式

spring常用的注入方式有哪些?

通过xml的注入方式和基于注解的注入方式有:

  • set方法注入
  • 属性注入
  • 构造器依赖注入

什么是 aop?

面向切面编程,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。

例子:

日志输出,不使用AOP的话就需要把日志的输出语句放在所有类中,方法中,但是有了AOP就可以把日志输出语句封装一个可重用模块,在以声明的方式将他们放在类中,每次使用类就自动完成了日志输出。

订单模块中,订单的状态有已创建、已支付 、已完成、已取消等,我们更改订单状态的同时,需要新增一条订单状态更改记录表,在这里我们使用了AOP。

  • 在更改状态的方法上加上我们自定义注解,注解的参数有不同的订单状态。
  • 使用@Aspect注解定义一个切面类。
  • 使用@Pointcut注解定义切点表达式定位到我们需要增强的方法上。
  • 编写核心业务代码切入点,就是我们增强的方法,对订单状态更改记录的增删改查。
  • 加上通知注解,指定我们增强的方法执行的顺序,常见的通知有前置通知,后置通知等等。

AOP原理

使用JDK动态代理和CGLIB代理

JDK动态代理是Java自带的功能,无需通过加载第三方类实现; CGLib是第三方提供的工具,基于ASM实现的,性能比较高;

动态代理:

在程序运行期,创建目标对象的代理对象并对目标对象中的方法进行功能性增强的一种技术。

可以理解为对对象中方法的动态拦截,在拦截方法的前后执行功能操作。

JDK动态代理:

JDK动态代理只提供接口的代理

核心是InvocationHandler接口和Proxy类

目标类必须要实现一个接口,代理类要实现InvocationHandler接口,重写invoke方法对原方法增强

通过Proxy.newProxyInstance方法获取代理类

CGLIB代理:

基于父类的动态代理

如果代理类没有实现InvocationHandler接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。

CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

什么是bean?

由Spring IoC容器管理的对象称为bean

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

配置bean的时候指定scope属性值

  • singleton:单例,默认作用域
    • 对象创建:当应用加载,创建容器时,对象就被创建
    • 对象运行:只要容器在,对象一直活着
    • 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
  • prototype:多例,每次请求都会每次创建一个新对象。
    • 对象创建:当使用对象时,创建新的对象实例
    • 对象运行:只要对象在使用中,就一直活着
    • 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
  • request:每次HTTP请求都会创建一个新的Bean,该bean仅在当前HTTP request内有效。
  • session:会话,同一个会话共享一个实例,不同会话使用不同的实例。
  • global-session:全局会话,所有会话共享一个实例。

Bean实例化?

  • 无参构造方法实例化,它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
  • 工厂静态方法实例化
  • 工厂普通方法实例化

spring 中的 bean 是线程安全的吗?

大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

解决方案:

  • 更改他的作用域(scope)类型为prototype,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
  • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。

spring 自动装配 bean 有哪些方式?

三种:根据名称(byName)、根据类型(byType)、根据构造函数(constructor)

bean的自动装配:

手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。采用自动装配将避免这些错误,并且使配置简单化。

手动配置依赖关系

<bean id="cat" class="com.test.Cat />
<bean id="dog" class="com.test.Dog />

<bean id="animal" class="com.test.Animal">
    <property name="cat" ref="cat" />
    <property name="dog" ref="dog" />
</bean>

自动装配

<bean id="cat" class="com.test.Cat" />
<bean id="dog" class="com.test.Dog" />

<bean id="animal" class="com.test.Animal"  autowire="byName"/>

spring注解

@Component
@Controller
@Service
@Repository
@Autowired
@Qualifier
@Resource
@Value
@Scope
@PostConstruct
@PreDestroy
@Configuration
@Bean
@PropertySource	
@ComponentScan

@Autowired 的作用是什么?

就是自动装配,交给spring管理,对类成员变量、方法及构造函数都可进行标注

@Autowired默认是按照类型装配注入的

默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

@Autowired和@Resource之间的区别?

  • @Autowired默认是按照类型装配注入的
  • @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
  • @Resource不是Spring的注解,JDK11以后完全移除了javax扩展导致不能使用@resource注解
  • @Qualifier结合@Autowired一起使用,根据名称进行依赖注入
  • @Resource 相当于@Autowired+@Qualifier,按照名称进行注入

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

  • @Component:使用在类上用于实例化Bean
  • @Controller:springMVC控制器,使用在web层类上用于实例化Bean
  • @Service:使用在service层类上用于实例化Bean
  • @Repository:使用在dao层类上用于实例化Bean

@Service、@Repository 是@Component注解的特化,因为它以更好的方式指定了意图。

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

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

说一下spring的事务?

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。

Spring支持的事务管理类型

  • 编程式事务:在代码中硬编码(不推荐使用)。
  • 声明式事务:注解和XML配置 @Transactional

Spring的事务传播行为

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

事务隔离级别

  • 读未提交:⼜称为脏读,⼀个事务可以读取到另⼀个事务未提交的数据(会出现脏读、不可重复读、幻读)。
  • 读已提交:⼜称为不可重复读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  • 可重复读:⼜称为幻读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  • 序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

说一下spring mvc 运行流程?

  • (1)用户发送请求至前端控制器DispatcherServlet;
  • (2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
  • (3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
  • (4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
  • (5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
  • (6)Handler执行完成返回ModelAndView;
  • (7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
  • (8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
  • (9)ViewResolver解析后返回具体View;
  • (10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  • (11)DispatcherServlet响应用户。

spring mvc 有哪些组件?

  • 前端控制器(DispatcherServlet):主要负责捕获来自客户端的请求和调度各个组件。
  • 处理器映射器(HandlerMapping):根据url查找后端控制器Handler。
  • 处理器适配器(HandlerAdapter):执行后端控制器(Handler),拿到后端控制器返回的结果ModelAndView后将结果返回给前端控制器DispatcherServlet。
  • 后端控制器(处理器)(Handler):主要负责处理前端请求,完成业务逻辑,生成ModelAndView对象返回给HandlerAdapter。
  • 视图解析器(ViewResolver):主要负责将从DispatcherServlet中拿到的ModelAndView对象进行解析,生成View对象返回给DispatcherServlet。

Spring MVC常用的注解有哪些?

  • @RequestMapping
  • @RequestBody
  • @ResponseBody
  • @Conntroller
  • @RestController
  • @PathVariable
  • @RequestParam

Spring Boot

SpringBoot自动配置的原理?

在Spring程序main方法中,添加@SpringBootApplication或者@EnableAutoConfiguration会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建的Spring容器中的bean。

Spring Boot的核心注解是哪些?他主由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,他也是SpringBoot的核心注解,主要组合包含了以下3个注解:

  • @SpringBootConfiguration:组合了@Configuration注解,实现配置文件的功能;
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置的功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class});
  • @ComponentScan:Spring组件扫描。

SpringBoot的核心配置文件有哪几个?他们的区别是什么?

SpringBoot的核心配置文件是application和bootstrap配置文件。

application配置文件这个容易理解,主要用于Spring Boot项目的自动化配置。

bootstrap配置文件有以下几个应用场景:

  • 使用Spring Cloud Config配置中心时,这时需要在bootstrap配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
  • 一些固定的不能被覆盖的属性;
  • 一些加密/解密的场景;

什么是Spring Boot Starter?有哪些常用的?如何自定义Spring Boot Starter?

和自动配置一样,Spring Boot Starter的目的也是简化配置,而Spring Boot Starter解决的是依赖管理配置复杂的问题,有了它,当我需要构建一个Web应用程序时,不必再遍历所有的依赖包,一个一个地添加到项目的依赖管理中,而是只需要一个配置spring-boot-starter-web

  • @ConfigurationProperties
  • @Configuration
  • @EnableConfigurationProperties(DemoProperties.class)
  • 在META-INF下创建spring.factory文件
  • install