java核心知识点整理--spring核心功能

1、Spring 核心功能演示
Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot,也是基于 Spring 实现的,SpringBoot 的诞生是为了让开发者更方便地使用 Spring,因此 Spring 在 Java 体系中的地位可谓首屈一指。
当然,如果想要把 Spring 所有功能都讲的一清二楚,远远不是一两篇文章能够做到的,但幸运的是,Spring 的基础资料可以很轻易的搜索到,那么我们本讲主要的目的就是把 Spring 中的核心知识点和常见面试题分享给大家,希望对大家能有所帮助。

Spring 介绍
Spring 是一个开源框架,为了解决企业应用程序开发复杂性而创建的,Spring 的概念诞生于 2002 年,于 2003 年正式发布第一个版本 Spring Framework 0.9。下面一起来看 Spring 各个版本的更新特性和它的发展变化吧。

Spring 1.x
此版本主要是为了解决企业应用程序开发复杂性而创建的,当时 J2EE 应用的经典架构是分层架构:表现层、业务层、持久层,最流行的组合就是 SSH(Struts、Spring、Hibernate)。
Spring 1.x 仅支持基于 XML 的配置,确保用户代码不依赖 Spring,它主要包含了以下功能模块:aop、beans、ejb、jdbc、jndi、orm、transation、validation、web 等。

Spring 2.x
Spring 2.x 的改动并不是很大,主要是在 Spring 1.x 的基础上增加了几个新模块,如 ehcache、jms、jmx、scripting、stereotype 等。

Spring 3.x
Spring 3.x 开始不止支持 XML 的配置,还扩展了基于 Java 类的配置,还增加了 Expression、Instructment、Tomcat、oxm 等组件,同时将原来的 Web 细分为:Portlet、Servlet。

Spring 4.x
Spring 4.x 扩充了 Groovy、Messaging、WebMvc、Tiles2、WebSocket 等功能组件,同时 Spring 还适配了 Java 版本,全面支持 Java 8.0、Lambda 表达式等。随着 RESTful 架构风格被越来越多的用户所采用,Spring 4.x 也提供了 RestController 等注解新特性。

Spring 5.x
Spring 5.x 紧跟 Java 相关技术的更新迭代,不断适配 Java 的新版本,同时不断重构优化自身核心框架代码,支持函数式、响应式编程模型等。

Spring 核心
Spring 核心包括以下三个方面:

控制反转(Ioc)
依赖注入(DI)
面向切面编程(AOP)
下面分别来看它的这些特性。

控制反转(IoC)
控制反转(Inversion of Control,IoC),顾名思义所谓的控制反转就是把创建对象的权利交给框架去控制,而不需要人为地去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。
比如,你去某地旅游不再用自己亲自为订购 A 酒店还是 B 酒店而发愁了,只需要把住店的需求告诉给某个托管平台,这个托管平台就会帮你订购一个既便宜又舒适的酒店,而这个帮你订购酒店的行为就可以称之为控制反转。

依赖注入(DI)
依赖注入(Dependency Injection,DI),是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

IoC 和 DI 的关系
IoC 是 Spring 中一个极为重要的概念,而 DI 则是实现 IoC 的方法和手段。
接下来,我们来看依赖注入的常见实现方式有哪些?
依赖注入的常见实现方式如下:

setter 注入
构造方法注入
注解注入
1)setter 注入
Java 代码:

public class UserController {
// 注入 UserService 对象
private UserService userService;
public void setUserService(UserService userService){
this.userService = userService;
}
}
XML 配置:

Bean 标签的常用属性说明:

id:为实例化对象起名称,根据 id 值可以得到我们配置的实例化对象,id 属性的名称原则上可以任意命名,但是能包含任何特殊符号;
class:创建对象所在类的全路径;
name:功能和 id 属性一样,但是现在一般不用;与 id 的区别在于:name 属性值里可以包含特殊符号,但是 id 不可以;
scope:一般最常用的有两个值: Singleton:单例模式,整个应用程序,只创建 bean 的一个实例;Prototype:原型模式,每次注入都会创建一个新的 bean 实例,Spring 默认的是单例模式。
2)构造方法注入
Java 代码:

public class UserController {
private UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
}
XML 配置:

3)注解注入 @Controller public class UserController { // 使用注解自动注入 @Autowired() private UserService userService; // do something } // 创建依赖对象 @Service public class UserService { // do something } 创建依赖对象的常见注解:@Component、@Controller、@Service、@Repository。

总结:可以看出注解的方式要比传统的 XML(setter 和构造器注入)实现注入更为方便,同时注解方式也是官方力推的依赖注入最佳使用方式。

面向切面编程(AOP)
面向切面编程(Aspect Oriented Programming,AOP),它就好比将系统按照功能分类,每一个类别就是一个“切面”,我们再针对不同的切面制定相应的规则,类似开发模式被称为面向切面编程。

AOP 使用场景
日志系统
安全统一效验
AOP 优点
集中处理某一类问题,方便维护
逻辑更加清晰
降低模块间的耦合度
AOP 相关概念
Join point:连接点,程序执行期间的某一个点,例如执行方法或处理异常时候的点,在 Spring AOP 中,连接点总是表示方法的执行。
Advice:通知,通知分为方法执行前通知,方法执行后通知、环绕通知等。许多 AOP 框架(包括 Spring)都将通知建模为拦截器,在连接点周围维护一系列拦截器(形成拦截器链),对连接点的方法进行增强。
Pointcut:切点,匹配连接点(Join point)的表达式,是 AOP 的核心,并且 Spring 默认使用 AspectJ 作为切入点表达式语言。
Aspect:切面,是一个跨越多个类的模块化的关注点,它是通知(Advice)和切点(Pointcut)合起来的抽象,它定义了一个切点(Pointcut)用来匹配连接点(Join point),也就是需要对需要拦截的那些方法进行定义。
Target object:目标对象,被一个或者多个切面(Aspect)通知的对象,也就是需要被 AOP 进行拦截对方法进行增强(使用通知)的对象,也称为被通知的对象。由于在 AOP 里面使用运行时代理,因而目标对象一直是被代理的对象。
AOP proxy:AOP 代理,为了实现切面(Aspect)功能使用 AOP 框架创建一个对象,在 Spring 框架里面一个 AOP 代理指的是 JDK 自身的动态代理或 CGLIB 实现的动态代理。
Weaving:把切面加入到对象,并创建出代理对象的过程。
Advisor:一个 Advisor 相当于一个小型的切面,不同的是它只有一个通知(Advice),Advisor 在事务管理里面会经常遇到。
AOP 代码实现
AOP 的示例我们就以开车为例,开车的完成流程是这样的:巡视车体及周围情况 → 发动 → 开车 → 熄火 → 锁车。

当然我们的主要目的是“开车”,但在开车之前和开完车之后,我们要做一些其他的工作,这些“其他”的工作,可以理解为 AOP 编程。

1)创建类和方法
package com.learning.aop;
import org.springframework.stereotype.Component;

@Component(“person”)
public class Person {
public void drive() {
System.out.println(“开车”);
}
}
2)创建 AOP 拦截
package com.learning.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class CarAop {
@Before(“execution(* com.learning.aop.Person.drive())”)
public void before() {
System.out.println(“巡视车体及周围情况”);
System.out.println(“发动”);
}
@After(“execution(* com.learning.aop.Person.drive())”)
public void after() {
System.out.println(“熄火”);
System.out.println(“锁车”);
}
}
3)XML 配置注入扫描包路径

<?xml version="1.0" encoding="UTF-8"?>


<context:component-scan base-package=“com.learning”/>
aop:aspectj-autoproxy/

4)创建测试类
package com.learning.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(“applicationContext.xml”);
Person landlord = context.getBean(“person”, Person.class);
landlord.drive();
}
}
运行测试代码,执行结果如下:

巡视车体及周围情况

发动

开车

熄火

锁车

AspectJ 注解说明:
@Before — 前置通知,在连接点方法前调用;
@Around — 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法;
@After — 后置通知,在连接点方法后调用;
@AfterReturning — 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常;
@AfterThrowing — 异常通知,当连接点方法异常时调用。
相关面试题
1.@Value 注解的作用是什么?
答:基于 @Value 的注解可以读取 properties 配置文件,使用如下:

@Value("#{configProperties[‘jdbc.username’]}")

private String userName;

以上为读取 configProperties 下的 jdbc.username 配置。

2.Spring 通知类型有哪些?
答:Spring 通知类型总共有 5 种:前置通知、环绕通知、后置通知、异常通知、最终通知。

前置通知(Before advice):在目标方法执行之前执行的通知。在某连接点( join point )之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
环绕通知(Around Advice):在目标方法执行之前和之后都可以执行额外代码的通知,也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
后置通知(After (finally) advice):目标方法执行之后(某连接点退出的时候)执行的通知(不论是正常返回还是异常退出)。
异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
最终通知(After returning advice):在某连接点(join point)正常完成后执行的通知,例如,一个方法没有抛出任何异常,正常返回。
3.怎么理解 Spring 中的 IOC 容器?
答:Spring IOC 就是把创建对象的权利交给框架去控制,而不需要人为的去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。

比如,去某地旅游不再用自己亲自为订购 A 酒店还是 B 酒店而发愁了,只需要把住店的需求告诉给某个托管平台,这个托管平台就会帮你订购一个既便宜又舒适的酒店,而这个帮你订购酒店的行为就可以称之为控制反转。

4.怎么理解 Spring 中的依赖注入?
答:依赖注入是指组件之间的依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

5.IoC 和 DI 有什么关系?
答:IoC 是 Spring 中一个极为重要的概念,提供了对象管理的功能,从而省去了人为创建麻烦,而 DI 正是实现 IoC 的方法和手段。

6.@Component 和 @Bean 有什么区别?
答:它们的作用对象不同:@Component 作用于类,而 @Bean 注解作用于方法。

@Component 通常是通过类路径扫描来自动侦测和装配对象到 Spring 容器中,比如 @ComponentScan 注解就是定义扫描路径中的类装配到 Spring 的 Bean 容器中;@Bean 注解是告诉 Spring 这是某个类的实例,当我需要用它的时把它给我,@Bean 注解比 @Component 注解自定义性更强,很多地方我们只能通过 @Bean 注解来注册 Bean,比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean 来实现,比如以下示例,只能通过 @Bean 注解来实现:

public class WireThirdLibClass {
@Bean
public ThirdLibClass getThirdLibClass() {
return new ThirdLibClass();
}
}
7.Spring 中 bean 的作用域有几种类型?
答:Spring 中 bean 的作用域有四种类型,如下列表:

单例(Singleton):整个应用程序,只创建 bean 的一个实例;
原型(Prototype):每次注入都会创建一个新的 bean 实例;
会话(Session):每个会话创建一个 bean 实例,只在 Web 系统中有效;
请求(Request):每个请求创建一个 bean 实例,只在 Web 系统中有效。
Spring 默认的是单例模式。

8.什么是 Spring 的内部 bean?
答:当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner Bean,在 Spring 的基于 XML 的配置元数据中,可以在 或 元素内使用 元素,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。

9.Spring 注入方式有哪些?
答:Spring 的注入方式包含以下五种:

setter 注入
构造方法注入
注解注入
静态工厂注入
实例工厂注入
其中最常用的是前三种,官方推荐使用的是注解注入,相对使用更简单,维护成本更低,更直观。

10.在 Spring 中如何操作数据库?
答:在 Spring 中操作数据库,可以使用 Spring 提供的 JdbcTemplate 对象,JdbcTemplate 类提供了很多便利的方法,比如把数据库数据转变成基本数据类型或对象,执行自定义的 SQL 语句,提供了自定义的数据错误处理等,JdbcTemplate 使用示例如下:

@Autowired
private JdbcTemplate jdbcTemplate;
// 新增
@GetMapping(“save”)
public String save(){
String sql = “INSERT INTO USER (USER_NAME,PASS_WORD) VALUES (‘laowang’,‘123’)”;
int rows = jdbcTemplate.update(sql);
return “执行成功,影响” + rows + “行”;
}
// 删除
@GetMapping(“del”)
public String del(int id){
int rows= jdbcTemplate.update(“DELETE FROM USER WHERE ID = ?”,id);
return “执行成功,影响” + rows + “行”;
}
// 查询
@GetMapping(“getMapById”)
public Map getMapById(Integer id){
String sql = “SELECT * FROM USER WHERE ID = ?”;
Map map= jdbcTemplate.queryForMap(sql,id);
return map;
}
11.Spring 的 JdbcTemplate 对象和 JDBC 有什么区别?
答:Spring 的 JdbcTemplate 是对 JDBC API 的封装,提供更多的功能和更便利的操作,比如 JdbcTemplate 拥有:

JdbcTemplate 是线程安全的;
实例化操作比较简单,仅需要传递 DataSource;
自动完成资源的创建和释放工作;
创建一次 JdbcTemplate,到处可用,避免重复开发。
12.Spring 有几种实现事务的方式?
答:Spring 实现事务有两种方式:编程式事务和声明式事务。
编程式事务,使用 TransactionTemplate 或 PlatformTransactionManager 实现,示例代码如下:

private final TransactionTemplate transactionTemplate;
public void add(User user) throws Exception{
// Spring编码式事务,回调机制
transactionTemplate.execute(new TransactionCallback() {
@Override
public Object doInTransaction(TransactionStatus status) {
try {
userMapper.insertSelective(user);
} catch (Exception e) {
// 异常,设置为回滚
status.setRollbackOnly();
throw e;
}
return null;
}
});
}
如果有异常,调用 status.setRollbackOnly() 回滚事务,否则正常执行 doInTransaction() 方法,正常提交事务。
如果事务控制的方法不需要返回值,就可以使用 TransactionCallbackWithoutResult(TransactionCallback 接口的抽象实现类)示例代码如下:

public void add(User user) throws Exception {
// Spring编码式事务,回调机制
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
userMapper.insertSelective(user);
} catch (Exception e) {
// 异常,设置为回滚
status.setRollbackOnly();
throw e;
}
}
});
}
声明式事务,底层是建立在 Spring AOP 的基础上,在方式执行前后进行拦截,并在目标方法开始执行前创建新事务或加入一个已存在事务,最后在目标方法执行完后根据情况提交或者回滚事务。
声明式事务的优点:不需要编程,减少了代码的耦合,在配置文件中配置并在目标方法上添加 @Transactional 注解来实现,示例代码如下:

@Transactional
public void save() {
User user = new User(“laowang”);
userMapper.insertSelective(user);
if (true) {
throw new RuntimeException(“异常”);
}
}
抛出异常,事务会自动回滚,如果方法正常执行,则会自动提交事务。

13.Spring 事务隔离级别有哪些?
答:Spring 的注入方式包含以下五种:

ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
默认值为 ISOLATION_DEFAULT 遵循数据库的事务隔离级别设置。

14.Spring 声明式事务无效可能的原因有哪些?
答:可能的原因如下:

MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事务的;
@Transactional 使用在非 public 方法上,@Transactional 注解只能支持 public 级别,其他类型声明的事务不会生效;
@Transactional 在同一个类中无事务方法 A() 内部调用有事务方法 B(),那么此时 B() 事物不会生效。Spring 中的 AOP 的底层实现原理是什么?
答:Spring AOP 的底层实现原理就是动态代理。Spring AOP 的动态代理有两种实现方式,对于接口使用的是 JDK 自带的动态代理来实现的,而对比非接口使用的是 CGLib 来实现的,关于动态代理的详细内容,可参考前面【反射和动态代理】的那篇文章。

15.Spring 中的 Bean 是线程安全的吗?
答:Spring 中的 Bean 默认是单例模式,Spring 框架并没有对单例 Bean 进行多线程的封装处理,因此默认的情况 Bean 并非是安全的,最简单保证 Bean 安全的举措就是设置 Bean 的作用域为 Prototype(原型)模式,这样每次请求都会新建一个 Bean。

16.说一下 Spring 中 Bean 的生命周期?
答:Spring 中 Bean 的生命周期如下:

① 实例化 Bean:对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 Bean 时,或初始化 Bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 Bean;
② 设置对象属性(依赖注入):实例化后的对象被封装在 BeanWrapper 对象中,紧接着 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入;
③ 处理 Aware 接口:Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean:
如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String BeanId) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是 Spring 工厂自身;
如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext) 方法,传入 Spring 上下文;
④ BeanPostProcessor:如果想对 Bean 进行一些自定义的处理,那么可以让 Bean 实现了 BeanPostProcessor 接口,那将会调用 postProcessBeforeInitialization(Object obj, String s) 方法;
⑤ InitializingBean 与 init-method:如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法;
⑥ 如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用 postProcessAfterInitialization(Object obj, String s) 方法;由于这个方法是在 Bean 初始化结束时调用的,因而可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。

⑦ DisposableBean:当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy() 方法;
⑧ destroy-method:最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
17.Spring 有哪些优点?
答:Spring 优点如下:

开源免费的热门框架,稳定性高、解决问题成本低;
方便集成各种优秀的框架;
降低了代码耦合性,通过 Spring 提供的 IoC 容器,我们可以将对象之间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合;
方便程序测试,在 Spring 里,测试变得非常简单,例如:Spring 对 Junit 的支持,可以通过注解方便的测试 Spring 程序;
降低 Java EE API 的使用难度,Spring 对很多难用的 Java EE API(如 JDBC、JavaMail、远程调用等)提供了一层封装,通过 Spring 的简易封装,让这些 Java EE API 的使用难度大为降低。
18.Spring 和 Struts 的区别?
答:Spring 和 Struts 区别如下:
Spring 特性如下:

具备 IOC/DI、AOP 等通用能力,提高研发效率
除了支持 Web 层建设以外,还提供了 J2EE 整体服务
方便与其他不同技术结合使用,如 Hibernate、MyBatis 等
Spring 拦截机制是方法级别
Struts 特性如下:

是一个基于 MVC 模式的一个 Web 层的处理
Struts 拦截机制是类级别
19.Spring、SpringBoot、SpringCloud 的区别是什么?
答:它们的区别如下:

Spring Framework 简称 Spring,是整个 Spring 生态的基础。
Spring Boot 是一个快速开发框架,让开发者可以迅速搭建一套基于 Spring 的应用程序,并且将常用的 Spring 模块以及第三方模块,如 MyBatis、Hibernate 等都做了很好的集成,只需要简单的配置即可使用,不需要任何的 XML 配置文件,真正做到了开箱即用,同时默认支持 JSON 格式的数据,使用 Spring Boot 进行前后端分离开发也非常便捷。
Spring Cloud 是一套整合了分布式应用常用模块的框架,使得开发者可以快速实现微服务应用。作为目前非常热门的技术,有关微服务的话题总是在各种场景下被大家讨论,企业的招聘信息中也越来越多地出现对于微服务架构能力的要求。
20.Spring 中都是用了哪些设计模式?
答:Spring 中使用的设计模式如下:

工厂模式:通过 BeanFactory、ApplicationContext 来创建 bean 都是属于工厂模式;
单例、原型模式:创建 bean 对象设置作用域时,就可以声明 Singleton(单例模式)、Prototype(原型模式);
察者模式:Spring 可以定义一下监听,如 ApplicationListener 当某个动作触发时就会发出通知;
责任链模式:AOP 拦截器的执行;
策略模式:在创建代理类时,如果代理的是接口使用的是 JDK 自身的动态代理,如果不是接口使用的是 CGLIB 实现动态代理。
总结
通过本节内容我们充分的了解了 Spring 的核心:IoC、DI、AOP,也是用代码演示了 Spring 核心功能的示例,其中可以发现的是 Spring 正在从之前的 XML 配置编程变为 Java 注解编程,注解编程让 Spring 更加轻量化简单化了,这一点在我们后面介绍 SpringBoot 的时候,会让你更加感同身受。对于开发者来说,只有真正掌握了 Spring,才能称得上是一名合格的 Java 工程师。当然,学习的目的是为了更好的应用,因此现在就一起动手实践起来吧。

2、Spring MVC 核心组件
Spring MVC 介绍
Spring MVC(Spring Web MVC)是 Spring Framework 提供的 Web 组件,它的实现基于 MVC 的设计模式:Controller(控制层)、Model(模型层)、View(视图层),提供了前端路由映射、视图解析等功能,让 Java Web 开发变得更加简单,也属于 Java 开发中必须要掌握的热门框架。

执行流程
Spring MVC 的执行流程如下:

客户端发送请求至前端控制器(DispatcherServlet)
前端控制器根据请求路径,进入对应的处理器
处理器调用相应的业务方法
处理器获取到相应的业务数据
处理器把组装好的数据交还给前端控制器
前端控制器将获取的 ModelAndView 对象传给视图解析器(ViewResolver)
前端控制器获取到解析好的页面数据
前端控制器将解析好的页面返回给客户端
流程如下图所示:

1

核心组件
Spring MVC 的核心组件如下列表所示:

DispatcherServlet:核心处理器(也叫前端控制器),负责调度其他组件的执行,可降低不同组件之间的耦合性,是整个 Spring MVC 的核心模块。
Handler:处理器,完成具体业务逻辑,相当于 Servlet 或 Action。
HandlerMapping:DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler。
HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
HandlerExecutionChain:处理器执行链,包括两部分内容,即 Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器设置)。
HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作包括表单数据的验证、数据类型的转换、将表单数据封装到 POJO 等,这一系列的操作,都是由 HandlerAdapter 来完成,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
ViewResolver:视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。
自动类型转换
自动类型转换指的是,Spring MVC 可以将表单中的字段,自动映射到实体类的对应属性上,请参考以下示例。

  1. JSP 页面代码
    <%@ page conntType=“text/html;charset=UTF-8” language=“java” %>
名称:
年龄:
  1. 编写实体类
    public class PersonDTO {
    private String name;
    private int age;

    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    this.age = age;
    }
    }

  2. 编写控制器
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    public class PersonController {
    @RequestMapping(value = “/add”, produces = “text/plain;charset=utf-8”)
    public String add(PersonVO person) {
    return person.getName() + “:” + person.getAge();
    }
    }

  3. 执行结果
    执行结果如下图所示:

2

中文乱码处理
业务的操作过程中可能会出现中文乱码的情况,以下是处理中文乱码的解决方案。
第一步,在 web.xml 添加编码过滤器,配置如下:

encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 encodingFilter /* 第二步,设置 RequestMapping 的 produces 属性,指定返回值类型和编码,如下所示:

@RequestMapping(value = “/add”, produces = “text/plain;charset=utf-8”)
拦截器
在 Spring MVC 中可以通过配置和实现 HandlerInterceptor 接口,来实现自己的拦截器。

  1. 配置全局拦截器
    在 Spring MVC 的配置文件中,添加如下配置:

mvc:interceptors

</mvc:interceptors>
2. 添加拦截器实现代码
拦截器的实现代码如下:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**

  • 拦截器
    **/
    public class MyInteceptor implements HandlerInterceptor {
    // 在业务处理器处理请求之前被调用
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
    System.out.println(“preHandle”);
    return true;
    }
    // 在业务处理器处理请求完成之后,生成视图之前执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println(“postHandle”);
    }
    // 在 DispatcherServlet 完全处理完请求之后被调用
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
    Object handler, Exception ex) throws Exception {
    System.out.println(“afterCompletion”);
    }
    }
    参数验证
  1. pom.xml 添加验证依赖包
    配置如下:
org.hibernate.validator hibernate-validator 6.0.17.Final 2. 开启注解验证 在 Spring MVC 的配置文件中,添加如下配置信息:

<mvc:annotation-driven />
3. 编写控制器
代码如下:

import com.google.gson.JsonObject;
import com.learning.pojo.PersonDTO;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class PersonController {
@RequestMapping(value = “/check”, produces = “text/plain;charset=utf-8”)
public String check(@Validated PersonDTO person, BindingResult bindResult) {
// 需要 import com.google.gson.Gson
JsonObject result = new JsonObject();
StringBuilder errmsg = new StringBuilder();
if (bindResult.hasErrors()) {
List errors = bindResult.getAllErrors();
for (ObjectError error : errors) {
errmsg.append(error.getDefaultMessage());
}
result.addProperty(“status”, -1);
} else {
result.addProperty(“status”, 1);
}
result.addProperty(“errmsg”, errmsg.toString());
return result.toString();
}

}
4. 编写实体类
代码如下:

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class PersonDTO {
@NotNull(message = “姓名不能为空”)
private String name;
@Min(value = 18,message = “年龄不能低于18岁”)
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
更多验证注解,如下所示:

注解 运行时检查
@AssertFalse 被注解的元素必须为 false
@AssertTrue 被注解的元素必须为 true
@DecimalMax(value) 被注解的元素必须为一个数字,其值必须小于等于指定的最大值
@DecimalMin(Value) 被注解的元素必须为一个数字,其值必须大于等于指定的最小值
@Digits(integer=, fraction=) 被注解的元素必须为一个数字,其值必须在可接受的范围内
@Future 被注解的元素必须是日期,检查给定的日期是否比现在晚
@Max(value) 被注解的元素必须为一个数字,其值必须小于等于指定的最大值
@Min(value) 被注解的元素必须为一个数字,其值必须大于等于指定的最小值
@NotNull 被注解的元素必须不为 null
@Null 被注解的元素必须为 null
@Past(java.util.Date/Calendar) 被注解的元素必须过去的日期,检查标注对象中的值表示的日期比当前早
@Pattern(regex=, flag=) 被注解的元素必须符合正则表达式,检查该字符串是否能够在 match 指定的情况下被 regex 定义的正则表达式匹配
@Size(min=, max=) 被注解的元素必须在制定的范围(数据类型:String、Collection、Map、Array)
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个 map,则对其中的值部分进行校验
@CreditCardNumber 对信用卡号进行一个大致的验证
@Email 被注释的元素必须是电子邮箱地址
@Length(min=, max=) 被注解的对象必须是字符串的大小必须在制定的范围内
@NotBlank 被注解的对象必须为字符串,不能为空,检查时会将空格忽略
@NotEmpty 被注释的对象必须不为空(数据:String、Collection、Map、Array)
@Range(min=, max=) 被注释的元素必须在合适的范围内(数据:BigDecimal、BigInteger、String、byte、short、int、long 和原始类型的包装类)
@URL(protocol=, host=, port=, regexp=, flags=) 被注解的对象必须是字符串,检查是否是一个有效的 URL,如果提供了 protocol、host 等,则该 URL 还需满足提供的条件
5. 执行结果
执行结果,如下图所示:

3

访问 Spring MVC 官方说明文档:http://1t.click/H7a

相关面试题

  1. 简述一下 Spring MVC 的执行流程?
    答:前端控制器(DispatcherServlet) 接收请求,通过映射从 IoC 容器中获取对应的 Controller 对象和 Method 方法,在方法中进行业务逻辑处理组装数据,组装完数据把数据发给视图解析器,视图解析器根据数据和页面信息生成最终的页面,然后再返回给客户端。

  2. POJO 和 JavaBean 有什么区别?
    答:POJO 和 JavaBean 的区别如下:

POJO(Plain Ordinary Java Object)普通 Java 类,具有 getter/setter 方法的普通类都就可以称作 POJO,它是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
JavaBean 是 Java 语言中的一种可重用组件,JavaBean 的构造函数和行为必须符合特定的约定:这个类必须有一个公共的缺省构造函数;这个类的属性使用 getter/setter 来访问,其他方法遵从标准命名规范;这个类应是可序列化的。
简而言之,当一个 POJO 可序列化,有一个无参的构造函数,它就是一个 JavaBean。

  1. 如何实现跨域访问?
    答:常见的跨域的实现方式有两种:使用 JSONP 或者在服务器端设置运行跨域。服务器运行跨域的代码如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的请求规则
registry.addMapping("/api/**");
}
};
}
}
4. 以下代码描述正确的是?
@RequestMapping(value="/list",params={“age=10”}
public String list(){
// do something
}
A:age 参数不传递的时候,默认值是 10
B:age 参数可以为空
C:age 参数不能为空
D:以上都不对

答:C
题目解析:params={“age=10”} 表示必须包含 age 参数,且值必须等于 10。

  1. @RequestMapping 注解的常用属性有哪些?
    答:@RequestMapping 常用属性如下:

value:指定 URL 请求的实际地址,用法:@RequestMapping(value="/index");
method:指定请求的 method 类型,如 GET/POST/PUT/DELETE 等,用法:@RequestMapping(value="/list",method=RequestMethod.POST);
params:指定请求参数中必须包含的参数名称,如果不存在该名称,则无法调用此方法,用法:@RequestMapping(value="/list",params={“name”,“age”})。
6. 访问以下接口不传递任何参数的情况下,执行的结果是?
@RequestMapping(value="/list")
@ResponseBody
public String list(int id){
return “id=”+id;
}
A:id=0
B:id=
C:页面报错 500
D:id=null

答:C
题目解析:页面报错会提示:可选的参数“id”不能转为 null,因为基本类型不能赋值 null,所以会报错。

7.访问页面时显示 403 代表的含义是?
A:服务器繁忙
B:找不到该页面
C:禁止访问
D:服务器跳转中

答:C
题目解析:常用 HTTP 状态码及对应的含义:

400:错误请求,服务器不理解请求的语法
401:未授权,请求要求身份验证
403:禁止访问,服务器拒绝请求
500:服务器内部错误,服务器遇到错误,无法完成请求
502:错误网关,服务器作为网关或代理,从上游服务器收到无效响应
504:网关超时,服务器作为网关或代理,但是没有及时从上游服务器收到请求
8.forward 和 redirect 有什么区别?
答:forward 和 redirect 区别如下:

forward 表示请求转发,请求转发是服务器的行为;redirect 表示重定向,重定向是客户端行为;
forward 是服务器请求资源,服务器直接访问把请求的资源转发给浏览器,浏览器根本不知道服务器的内容是从哪来的,因此它的地址栏还是原来的地址;redirect 是服务端发送一个状态码告诉浏览器重新请求新的地址,因此地址栏显示的是新的 URL;
forward 转发页面和转发到的页面可以共享 request 里面的数据;redirect 不能共享数据;
从效率来说,forward 比 redirect 效率更高。
9. 访问以下接口不传递任何参数的情况下,执行的结果是?
@RequestMapping(value="/list")
@ResponseBody
public String list(Integer id){
return “id=”+id;
}
A:id=0
B:id=
C:页面报错 500
D:id=null

答:D
题目解析:包装类可以赋值 null,不会报错。

  1. Spring MVC 中如何在后端代码中实现页面跳转?
    答:在后端代码中可以使用 forward:/index.jsp 或 redirect:/index.jsp 完成页面跳转,前者 URL 地址不会发生改变,或者 URL 地址会发生改变,完整跳转代码如下:

@RequestMapping("/redirect")
public String redirectTest(){
return “redirect:/index.jsp”;
}
11. Spring MVC 的常用注解有哪些?
答:Spring MVC 的常用注解如下:

@Controller:用于标记某个类为控制器;
@ResponseBody :标识返回的数据不是 html 标签的页面,而是某种格式的数据,如 JSON、XML 等;
@RestController:相当于 @Controller 加 @ResponseBody 的组合效果;
@Component:标识为 Spring 的组件;
@Configuration:用于定义配置类;
@RequestMapping:用于映射请求地址的注解;
@Autowired:自动装配对象;
@RequestHeader:可以把 Request 请求的 header 值绑定到方法的参数上。
12. 拦截器的使用场景有哪些?
答:拦截器的典型使用场景如下:

日志记录:可用于记录请求日志,便于信息监控和信息统计;
权限检查:可用于用户登录状态的检查;
统一安全处理:可用于统一的安全效验或参数的加密 / 解密等。
13. Spring MVC 如何排除拦截目录?
答:在 Spring MVC 的配置文件中,添加 ,用于排除拦截目录,完整配置的示例代码如下:

mvc:interceptors
mvc:interceptor
<mvc:mapping path="/" />

<mvc:exclude-mapping path="/api/
" />

</mvc:interceptor>
</mvc:interceptors>
14.@Validated 和 @Valid 有什么区别 ?
答:@Validated 和 @Valid 都用于参数的效验,不同的是:

@Valid 是 Hibernate 提供的效验机制,Java 的 JSR 303 声明了 @Valid 这个类接口,而 Hibernate-validator 对其进行了实现;@Validated 是 Spring 提供的效验机制,@Validation 是对 @Valid 进行了二次封装,提供了分组功能,可以在参数验证时,根据不同的分组采用不同的验证机制;
@Valid 可用在成员对象的属性字段验证上,而 @Validated 不能用在成员对象的属性字段验证上,也就是说 @Validated 无法提供嵌套验证。
15.Spring MVC 有几种获取 request 的方式?
答:Spring MVC 获取 request 有以下三种方式:

① 从请求参数中获取

示例代码:

@RequestMapping("/index")
@ResponseBody
public void index(HttpServletRequest request){
  // do something
}
该方法实现的原理是 Controller 开始处理请求时,Spring 会将 request 对象赋值到方法参数中。

② 通过 RequestContextHolder上下文获取 request 对象

示例代码:

@RequestMapping("/index")
@ResponseBody
public void index(){
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
// do something
}
③ 通过自动注入的方式

@Controller
public class HomeController{
@Autowired
private HttpServletRequest request; // 自动注入 request 对象
// do something
}
总结
本文我们了解了 Spring MVC 运行的 8 个步骤和它的 8 大核心组件,也尝试了 Spring MVC 方面的类型转换,可将表单自动转换为实体对象,也使用 Hibernate 的验证功能优雅地实现了参数的验证,还可以通过配置和实现 HandlerInterceptor 接口来自定义拦截器,相信有了这些知识,可以帮助我们更高效地开发 Web 和接口项目。

3、Spring Boot 的创建方式
为什么要用 Spring Boot?
Spring Boot 来自于 Spring 大家族,是 Spring 官方团队(Pivotal 团队)提供的全新框架,它的诞生解决了 Spring 框架使用较为繁琐的问题。Spring Boot 的核心思想是约定优于配置,让开发人员不需要配置任何 XML 文件,就可以像 Maven 整合 Jar 包一样,整合并使用所有框架。

Spring Boot 特性

秒级构建一个项目;
便捷的对外输出格式,如 REST API、WebSocket、Web 等;
简洁的安全集成策略;
内嵌容器运行,如 Tomcat、Jetty;
强大的开发包,支持热启动;
自动管理依赖;
自带应用监控。
Spring Boot 2 对系统环境的要求

Java 8+
Gradle 4+ or Maven 3.2+
Tomcat 8+
Spring Boot 使用
在开始之前,我们先来创建一个Spring Boot 项目。

Spring Boot 有两种快速创建的方式:Spring 官网在线网站创建和 IntelliJ IDEA 的 Spring Initializr 创建,下面分别来看。

创建 Spring Boot 项目
1)在线网站创建
在浏览器输入 https://start.spring.io,页面打开如下图所示:

1

填写相应的项目信息,选择对应的 Spring Boot 和 Java 版本点击 “Generate the project”按钮下载项目压缩文件,解压后用 IDEA 打开即可。

其中 Group 和 Artifact 是 Maven 项目用来确认依赖项目的标识,比如:

org.springframework spring-core 4.1.6.RELEASE Group 对应的是配置文件的 groupId,相当于项目的包名;而 Artifact 对应的是配置文件的 artifactId,相当于项目名。

2)使用 IntelliJ IDEA 创建
① 新建项目 → 选择 Spring Initialzr,如下图所示:

2

② 点击 Next 按钮,填写对应的项目信息(和在线网站创建的字段基本相同),如下图所示:

3

③ 点击 Next 按钮,选择相应的依赖信息,如下图所示:

4

④ 点击 Next 按钮,选择项目保存的路径,点击 Finish 创建项目完成,如下图所示:

5

创建一个 Web 应用
1)pom.xml 中添加 Web 模块的依赖,如下所示:

org.springframework.boot spring-boot-starter-web 2)创建后台代码

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
@RequestMapping("/index")
public String index(String name) {
return "Hello, " + name;
}
}
3)启动并访问项目

项目的启动类是标识了 @Spring BootApplication 的类,代码如下所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootlearningApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootlearningApplication.class, args);
}
}
启动并访问 http://localhost:8080/index?name=laowang 效果如下:

6

到目前为止 Spring Boot 的项目就创建并正常运行了。

设置配置文件
Spring Boot 的配置文件,是 resources 目录下 application.properties 文件,如下图所示:

7

可以在配置文件中设置很多关于 Spring 框架的配置,格式如下配置所示:

项目运行端口

server.port=8086

请求编码格式

server.tomcat.uri-encoding=UTF-8
Spring Boot 的其他功能开发和 Spring 相同(Spring Boot 2 是基于 Spring Framework 5 构建的),本文就不过多的介绍了,感兴趣的朋友可以点击这里查看

Spring Boot 发布
Spring Boot 项目的发布方式有两种:

内置容器运行
外置容器(Tomcat)运行
内置容器运行
1)打包应用
使用窗口命令,在 pom.xml 同级目录下:

mvn clean package -Dmaven.test.skip=true

Dmaven.test.skip=true 表示不执行测试用例,也不编译测试用例类。

2)启动应用
后台启动 Java 程序, 命令如下:

nohup java -jar springbootlearning-0.0.1-SNAPSHOT.jar &

停止程序

首先查询 Java 程序的 pid

ps -ef|grep java

再停止程序

kill -9 pid

操作如下图所示:

8

扩展内容

指定程序运行日志文件

nohup java -jar springbootlearning-0.0.1-SNAPSHOT.jar 1>>logs 2>>errlog &

其中:

1:表示普通日志
2:表示错误日志
外置容器(Tomcat)运行
1)排除内置 Tomcat

org.springframework.boot
spring-boot-starter-tomcat
provided

将 scope 属性设置为 provided,表示打包不会包含此依赖。

2)配置启动类
在项目的启动类中继承 Spring BootServletInitializer 并重写 configure() 方法:

@SpringBootApplication
public class PackageApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PackageApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(PackageApplication.class, args);
}
}
3)打包应用
使用窗口命令,在 pom.xml 同级目录下:

mvn clean package -Dmaven.test.skip=true

4)部署应用
打包完成会在 target 目录下生成:项目名 + 版本号.war 文件,复制到 Tomcat 的 webapps 目录下,运行 Tomcat 即可。

相关面试题
1.Spring Boot 2.0 支持最低的 JDK 版本是?
A:JDK 6
B:JDK 7
C:JDK 8
D:JDK 9

答:C

2.Spring、Spring Boot、Spring Cloud 是什么关系?
答:它们都是来自于 Spring 大家庭,Spring Boot 是在 Spring 框架的基础上开发而来,让更加方便使用 Spring;Spring Cloud 是依赖于 Spring Boot 而构建的一套微服务治理框架。

3.Spring Boot 项目有哪些优势?
答:Spring Boot 项目优势如下:

开发变得简单,提供了丰富的解决方案,快速集成各种解决方案提升开发效率;
配置变得简单,提供了丰富的 Starters,集成主流开源产品往往只需要简单的配置即可;
部署变得简单,其本身内嵌启动容器,仅仅需要一个命令即可启动项目,结合 Jenkins、Docker 自动化运维非常容易实现;
监控变得简单,自带监控组件,使用 Actuator 轻松监控服务各项状态。
4.如何将 Spring Boot 项目打包成 war 包?
答:在 pom.xml 里设置 war 。

5.在 Maven 项目中如何修改打包名称?
答:在 pom.xml 文件的 build 节点中,添加 finalName 节点并设置为要的名称即可,配置如下:

warName 6.Ant、Maven、Gradle 有什么区别? 答:Ant、Maven、Gradle 是 Java 领域中主要有三大构建工具,它们的区别如下:

Ant(AnotherNeatTool)诞生于 2000 年,是由 Java 编写,采用 XML 作为构建脚本,这样就允许你在任何环境下运行构建。Ant 是 Java 领域最早的构建工具,不过因为操作复杂,慢慢的已经被淘汰了;
Maven 诞生于 2004 年,目的是解决程序员使用 Ant 所带来的一些问题,它的好处在于可以将项目过程规范化、自动化、高效化以及强大的可扩展性;
Gradle 诞生于 2009 年,是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具。它使用一种基于 Groovy 的特定领域语言来声明项目设置,而不是传统的 XML。结合了前两者的优点,在此基础之上做了很多改进,它具有 Ant 的强大和灵活,又有 Maven 的生命周期管理且易于使用。
Spring Boot 官方支持 Maven 和 Gradle 作为项目构建工具。Gradle 虽然有更好的理念,但是相比 Maven 来讲其行业使用率偏低,并且 Spring Boot 官方默认使用 Maven。

7.Maven 如何设置发布的包名?
答:在 build 节点下设置 finalName 就是发布的包名,如下代码所示:

biapi 8.Spring Boot 热部署有几种方式? 答:Spring Boot 热部署主要有两种方式:Spring Loaded、Spring-boot-devtools。

方式 1:Spring Loaded

在 pom.xml 文件中添加如下依赖:

org.springframework.boot spring-boot-maven-plugin org.springframework springloaded 1.2.6.RELEASE 此处为入口类 方式 2:Spring-boot-devtools

在 pom.xml 文件中添加如下依赖:

org.springframework.boot spring-boot-devtools provided true 9.Spring Boot 2.0 可以在 Tomcat 7 运行吗?为什么? 答:Spring Boot 2.0 无法在 Tomcat 7 上运行。因为 Spring Boot 2.0 使用的是 Spring Framework 5,Spring Framework 5 使用的是 Servlet 3.1,而 Tomcat 7 最高支持到 Servlet 3.0,所以 Spring Boot 2.0 无法在 Tomcat 7 上运行。

10.如何使用 Jetty 代替 Tomcat?
答:在 spring-boot-starter-web 移除现有的依赖项,添加 Jetty 依赖,配置如下:

org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty 11.Spring Boot 不支持以下哪个内嵌容器? A:Tomcat B:Jetty C:Undertow D:Nginx

答:D

题目解析:Jetty 容器支持如下:

org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty Undertow 容器支持如下: org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-undertow 12.Spring Boot 中配置文件有几种格式? 答:Spring Boot 中有 .properties 和 .yml 两种配置文件格式,它们主要的区别是书写格式不同。

.properties 配置文件格式如下:

app.user.name = hellojava
.yml 配置文件格式如下:

app:
user:
name: hellojava
13.项目中有两个配置 application.properties 和 application.yml,以下说法正确的是?
A:application.properties 的内容会被忽略,只会识别 application.yml 的内容。
B:两个配置文件同时有效,有相同配置时,以 application.properties 文件为主。
C:application.yml 的内容会被忽略,只会识别 application.properties 的内容。
D:两个配置文件同时有效,有相同配置时,以 application.yml 文件为主。

答:B

14.RequestMapping 和 GetMapping 有什么不同?
答:RequestMapping 和 GetMapping 区别如下:

RequestMapping 可以支持 GET、POST、PUT 请求;
GetMapping 是一个组合注解,相当于 @RequestMapping(method = RequestMethod.GET)。
15.以下关于 @RestController 和 @Controller 说法正确的?
A:@Controller 返回 JSON 数据
B:@RestController 返回 JSON 数据
C:@APIController 返回 JSON 数据
D:以上都对

答:B

16.Spring Cache 常用的缓存注解有哪些?
答:Spring Cache 常用注解如下:

@Cacheable:用来声明方法是可缓存,将结果存储到缓存中以便后续使用相同参数调用时不需执行实际的方法,直接从缓存中取值;
@CachePut:使用它标注的方法在执行前,不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中;
CacheEvict:是用来标注在需要清除缓存元素的方法或类上的,当标记在一个类上时表示其中所有方法的执行都会触发缓存的清除操作。
17.Spring Boot Admin 和 Spring Boot Actuator 的关系是什么?
答:Spring Boot Admin 使用了 Spring Boot Actuator 接口进行 UI 美化封装的监控工具,它以图形化的方式查询单个应用的详细状态,也可以使用 Spring Boot Admin 来监控整个集群的状态。

18.如何理解 Spring Boot 中的 Stater?
答:Stater 可以理解为启动器,它是方便开发者快速集成其他框架到 Spring 中的一种技术。比如,spring-boot-starter-data-jpa 就是把 JPA 快速集成到 Spring 中。

19.常见的 starter 有哪些?
答:常见的 starter 如下:

spring-boot-starter-web:Web 开发支持
spring-boot-starter-data-jpa:JPA 操作数据库支持
spring-boot-starter-data-redis:Redis 操作支持
spring-boot-starter-data-solr:Solr 权限支持
mybatis-spring-boot-starter:MyBatis 框架支持
20.Spring Boot Starter JDBC 和 Spring JDBC 有什么关系?
答:spring-boot-starter-jdbc 是 Spring Boot 针对 JDBC 的使用提供了对应的 Starter 包,在 Spring JDBC 上做了进一步的封装,方便在 Spring Boot 生态中更好的使用 JDBC。

21.Spring Boot 有哪几种读取配置的方式?
答:Spring Boot 可以通过 @Value、@Environment、@ConfigurationProperties 这三种方式来读取。

例如,配置文件内容如下:

app.name=中文
① Value 方式

@Value("${app.name}")
private String appName;
② Environment 方式

public class HelloController {
@Autowired
private Environment environment;
@RequestMapping("/index")
public String index(String hiName) {
// 读取配置文件
String appName = environment.getProperty(“app.name”);
return “Hello, " + hiName + " |@” + appName;
}
}
③ ConfigurationProperties 方式

@ConfigurationProperties(prefix = “app”)
public class HelloController {
// 读取配置文件,必须有 setter 方法
private String name;
public void setName(String name) {
this.name = name;
}
@RequestMapping("/index")
public String index(String hiName) {
System.out.println(“appname:” + name);
return “Hello, " + hiName + " |@” + appName;
}
}
22.使用 @Value 读取中文乱码是什么原因?如何处理?
答:这是因为配置文件的编码格式导致的,需要把编码格式设置为 UTF-8,如下图所示:

9

设置完成之后,重新启动 IDEA 就可以正常显示中文了。

总结
通过本文我们学习了 Spring Boot 的两种创建方式:在线网站创建和 IntelliJ IDEA 方式创建。知道了 Spring Boot 发布的两种方式:内置容器和外置 Tomcat,知道了 Spring Boot 项目特性,以及配置文件 .properties 和 .yml 的差异,掌握了读取配置文件的三种方式:@Value、@Environment、@ConfigurationProperties。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值