文章目录
-
- 1. Spring Boot
- 2. Spring
-
-
- 2.1 请你说说Spring的核心是什么
- 2.2 说一说你对Spring容器的了解
- 2.3 说一说你对BeanFactory的了解
- 2.4 说一说你对Spring IOC的理解
- 2.5 Spring是如何管理Bean的?
- 2.6 介绍Bean的作用域
- 2.7 说一说Bean的生命周期
- 2.8 Spring是怎么解决循环依赖的?
- 2.9 @Autowired和@Resource注解有什么区别?
- 2.10 Spring中默认提供的单例是线程安全的吗?
- 2.11 说一说你对Spring AOP的理解
- 2.12 请你说说AOP的应用场景
- 2.13 Spring AOP不能对哪些类进行增强?
- 2.14 JDK动态代理和CGLIB有什么区别?
- 2.15 既然有没有接口都可以用CGLIB,为什么Spring还要使用JDK动态代理?
- 2.16 Spring如何管理事务?
- 2.17 Spring的事务传播方式有哪些?
- 2.18 Spring的事务如何配置,常用注解有哪些?
- 2.19 说一说你对声明式事务的理解
-
- 3. Spring MVC
- 4. MyBatis
- 5. 其他
-
-
- 5.1 cookie和session的区别是什么?
- 5.2 cookie和session各自适合的场景是什么?
- 5.3 请介绍session的工作原理
- 5.4 get请求与post请求有什么区别?
- 5.5 get请求的参数能放到body里面吗?
- 5.6 post不幂等是为什么?
- 5.7 页面报400错误是什么意思?
- 5.8 请求数据出现乱码该怎么处理?
- 5.9 如何在SpringBoot框架下实现一个定时任务?
- 5.10 调用接口时要记录日志,该怎么设计?
- 5.11 了解Spring Boot JPA吗?
- 5.7 页面报400错误是什么意思?
- 5.8 请求数据出现乱码该怎么处理?
- 5.9 如何在SpringBoot框架下实现一个定时任务?
- 5.10 调用接口时要记录日志,该怎么设计?
- 5.11 了解Spring Boot JPA吗?
-
1. Spring Boot
1.1 说说你对Spring Boot的理解
参考答案
从本质上来说,Spring Boot就是Spring,它做了那些没有它你自己也会去做的Spring Bean配置。Spring Boot使用“习惯优于配置”的理念让你的项目快速地运行起来,使用Spring Boot很容易创建一个能独立运行、准生产级别、基于Spring框架的项目,使用Spring Boot你可以不用或者只需要很少的Spring配置。
简而言之,Spring Boot本身并不提供Spring的核心功能,而是作为Spring的脚手架框架,以达到快速构建项目、预置三方配置、开箱即用的目的。Spring Boot有如下的优点:
- 可以快速构建项目;
- 可以对主流开发框架的无配置集成;
- 项目可独立运行,无需外部依赖Servlet容器;
- 提供运行时的应用监控;
- 可以极大地提高开发、部署效率;
- 可以与云计算天然集成。
1.2 Spring Boot Starter有什么用?
参考答案
Spring Boot通过提供众多起步依赖(Starter)降低项目依赖的复杂度。起步依赖本质上是一个Maven项目对象模型(Project Object Model, POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。很多起步依赖的命名都暗示了它们提供的某种或某类功能。
举例来说,你打算把这个阅读列表应用程序做成一个Web应用程序。与其向项目的构建文件里添加一堆单独的库依赖,还不如声明这是一个Web应用程序来得简单。你只要添加Spring Boot的Web起步依赖就好了。
1.3 介绍Spring Boot的启动流程
参考答案
首先,Spring Boot项目创建完成会默认生成一个名为 *Application
的入口类,我们是通过该类的main方法启动Spring Boot项目的。在main方法中,通过SpringApplication的静态方法,即run方法进行SpringApplication类的实例化操作,然后再针对实例化对象调用另外一个run方法来完成整个项目的初始化和启动。
SpringApplication调用的run方法的大致流程,如下图:
其中,SpringApplication在run方法中重点做了以下操作:
- 获取监听器和参数配置;
- 打印Banner信息;
- 创建并初始化容器;
- 监听器发送通知。
当然,除了上述核心操作,run方法运行过程中还涉及启动时长统计、异常报告、启动日志、异常处理等辅助操作。比较完整的流程,可以参考如下源代码:
public ConfigurableApplicationContext run(String... args) {
// 创建StopWatch对象,用于统计run方法启动时长。
StopWatch stopWatch = new StopWatch();
// 启动统计
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 配置Headless属性
configureHeadlessProperty();
// 获得SpringApplicationRunListener数组,
// 该数组封装于SpringApplicationRunListeners对象的listeners中。
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听,遍历SpringApplicationRunListener数组每个元素,并执行。
listeners.starting();
try {
// 创建ApplicationArguments对象
ApplicationArguments applicationArguments =
new DefaultApplicationArguments(args);
// 加载属性配置,包括所有的配置属性。
ConfigurableEnvironment environment =
prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建容器
context = createApplicationContext();
// 异常报告器
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备容器,组件对象之间进行关联。
prepareContext(context, environment,
listeners, applicationArguments, printedBanner);
// 初始化容器
refreshContext(context);
// 初始化操作之后执行,默认实现为空。
afterRefresh(context, applicationArguments);
// 停止时长统计
stopWatch.stop();
// 打印启动日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 通知监听器:容器完成启动。
listeners.started(context);
// 调用ApplicationRunner和CommandLineRunner的运行方法。
callRunners(context, applicationArguments);
} catch (Throwable ex) {
// 异常处理
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 通知监听器:容器正在运行。
listeners.running(context);
} catch (Throwable ex) {
// 异常处理
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
1.4 Spring Boot项目是如何导入包的?
参考答案
通过Spring Boot Starter导入包。
Spring Boot通过提供众多起步依赖(Starter)降低项目依赖的复杂度。起步依赖本质上是一个Maven项目对象模型(Project Object Model, POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。很多起步依赖的命名都暗示了它们提供的某种或某类功能。
举例来说,你打算把这个阅读列表应用程序做成一个Web应用程序。与其向项目的构建文件里添加一堆单独的库依赖,还不如声明这是一个Web应用程序来得简单。你只要添加Spring Boot的Web起步依赖就好了。
1.5 请描述Spring Boot自动装配的过程
参考答案
使用Spring Boot时,我们只需引入对应的Starters,Spring Boot启动时便会自动加载相关依赖,配置相应的初始化参数,以最快捷、简单的形式对第三方软件进行集成,这便是Spring Boot的自动配置功能。Spring Boot实现该运作机制锁涉及的核心部分如下图所示:
整个自动装配的过程是:Spring Boot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中注册的各种AutoConfiguration类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件(Starters提供的依赖、配置或Spring容器中是否存在某个Bean等)时,实例化该AutoConfiguration类中定义的Bean(组件等),并注入Spring容器,就可以完成依赖框架的自动配置。
1.6 说说你对Spring Boot注解的了解
参考答案
@SpringBootApplication注解:
在Spring Boot入口类中,唯一的一个注解就是@SpringBootApplication。它是Spring Boot项目的核心注解,用于开启自动配置,准确说是通过该注解内组合的@EnableAutoConfiguration开启了自动配置。
@EnableAutoConfiguration注解:
@EnableAutoConfiguration的主要功能是启动Spring应用程序上下文时进行自动配置,它会尝试猜测并配置项目可能需要的Bean。自动配置通常是基于项目classpath中引入的类和已定义的Bean来实现的。在此过程中,被自动配置的组件来自项目自身和项目依赖的jar包中。
@Import注解:
@EnableAutoConfiguration的关键功能是通过@Import注解导入的ImportSelector来完成的。从源代码得知@Import(AutoConfigurationImportSelector.class)是@EnableAutoConfiguration注解的组成部分,也是自动配置功能的核心实现者。
@Conditional注解:
@Conditional注解是由Spring 4.0版本引入的新特性,可根据是否满足指定的条件来决定是否进行Bean的实例化及装配,比如,设定当类路径下包含某个jar包的时候才会对注解的类进行实例化操作。总之,就是根据一些特定条件来控制Bean实例化的行为。
@Conditional衍生注解:
在Spring Boot的autoconfigure项目中提供了各类基于@Conditional注解的衍生注解,它们适用不同的场景并提供了不同的功能。通过阅读这些注解的源码,你会发现它们其实都组合了@Conditional注解,不同之处是它们在注解中指定的条件(Condition)不同。
- @ConditionalOnBean:在容器中有指定Bean的条件下。
- @ConditionalOnClass:在classpath类路径下有指定类的条件下。
- @ConditionalOnCloudPlatform:当指定的云平台处于active状态时。
- @ConditionalOnExpression:基于SpEL表达式的条件判断。
- @ConditionalOnJava:基于JVM版本作为判断条件。
- @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置。
- @ConditionalOnMissingBean:当容器里没有指定Bean的条件时。
- @ConditionalOnMissingClass:当类路径下没有指定类的条件时。
- @ConditionalOnNotWebApplication:在项目不是一个Web项目的条件下。
- @ConditionalOnProperty:在指定的属性有指定值的条件下。
- @ConditionalOnResource:类路径是否有指定的值。
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个或者有多个但是指定了首选的Bean时。
- @ConditionalOnWebApplication:在项目是一个Web项目的条件下。
2. Spring
2.1 请你说说Spring的核心是什么
参考答案
Spring框架包含众多模块,如Core、Testing、Data Access、Web Servlet等,其中Core是整个Spring框架的核心模块。Core模块提供了IoC容器、AOP功能、数据绑定、类型转换等一系列的基础功能,而这些功能以及其他模块的功能都是建立在IoC和AOP之上的,所以IoC和AOP是Spring框架的核心。
IoC(Inversion of Control)是控制反转的意思,这是一种面向对象编程的设计思想。在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间的耦合度过高,在一个大型的项目中这十分的不利于代码的维护。IoC则可以解决这种问题,它可以帮我们维护对象与对象之间的依赖关系,降低对象之间的耦合度。
说到IoC就不得不说DI(Dependency Injection),DI是依赖注入的意思,它是IoC实现的实现方式,就是说IoC是通过DI来实现的。由于IoC这个词汇比较抽象而DI却更直观,所以很多时候我们就用DI来代替它,在很多时候我们简单地将IoC和DI划等号,这是一种习惯。而实现依赖注入的关键是IoC容器,它的本质就是一个工厂。
AOP(Aspect Oriented Programing)是面向切面编程思想,这种思想是对OOP的补充,它可以在OOP的基础上进一步提高编程的效率。简单来说,它可以统一解决一批组件的共性需求(如权限检查、记录日志、事务管理等)。在AOP思想下,我们可以将解决共性需求的代码独立出来,然后通过配置的方式,声明这些代码在什么地方、什么时机调用。当满足调用条件时,AOP会将该业务代码织入到我们指定的位置,从而统一解决了问题,又不需要修改这一批组件的代码。
2.2 说一说你对Spring容器的了解
参考答案
Spring主要提供了两种类型的容器:BeanFactory和ApplicationContext。
- BeanFactory:是基础类型的IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延
迟初始化策略。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。 - ApplicationContext:它是在BeanFactory的基础上构建的,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容
器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。
2.3 说一说你对BeanFactory的了解
参考答案
BeanFactory是一个类工厂,与传统类工厂不同的是,BeanFactory是类的通用工厂,它可以创建并管理各种类的对象。这些可被创建和管理的对象本身没有什么特别之处,仅是一个POJO,Spring称这些被创建和管理的Java对象为Bean。并且,Spring中所说的Bean比JavaBean更为宽泛一些,所有可以被Spring容器实例化并管理的Java类都可以成为Bean。
BeanFactory是Spring容器的顶层接口,Spring为BeanFactory提供了多种实现,最常用的是XmlBeanFactory。但它在Spring 3.2中已被废弃,建议使用XmlBeanDefinitionReader、DefaultListableBeanFactory替代。BeanFactory最主要的方法就是 getBean(String beanName)
,该方法从容器中返回特定名称的Bean。
2.4 说一说你对Spring IOC的理解
参考答案
IoC(Inversion of Control)是控制反转的意思,这是一种面向对象编程的设计思想。在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间的耦合度过高,在一个大型的项目中这十分的不利于代码的维护。IoC则可以解决这种问题,它可以帮我们维护对象与对象之间的依赖关系,降低对象之间的耦合度。
说到IoC就不得不说DI(Dependency Injection),DI是依赖注入的意思,它是IoC实现的实现方式,就是说IoC是通过DI来实现的。由于IoC这个词汇比较抽象而DI却更直观,所以很多时候我们就用DI来代替它,在很多时候我们简单地将IoC和DI划等