Spring
什么是Spring IoC
IoC翻译过来是控制反转。控制指的是对象创建「实例化、管理」的权利;反转指的是控制权交给外部环境「Spring框架、IoC容器」。IoC的思想就是将原本在程序中手动创建对象的控制权交由Spring框架处理。
在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
在Spring中,IoC容器是Spring用来实现IoC的载体,IoC容器实际上就是个Map,Map中存放的是各种对象。
什么是Spring Bean
简单来说,Bean代指的就是那些被 IoC 容器所管理的对象。我们需要告诉IoC容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是XML文件、注解或者Java配置类。
将一个类声明为Bean的注解
@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service
: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller
: 对应 Spring MVC 控制层,主要用于接受用户请求并调用Service
层返回数据给前端页面
@Autowired注入Bean
Autowired
属于 Spring 内置的注解,默认的注入方式为 byType
(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)。
这会有什么问题呢? 当一个接口存在多个实现类的话,byType
这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。这种情况下,注入方式会变为 byName
(根据名称进行匹配),这个名称通常就是类名(首字母小写)。
举个例子,SmsService
接口有两个实现类。
1 | // 报错,byName 和 byType 都无法匹配到 bean |
建议通过@Qualifier
注解来显式执行名称。
@Resource注入Bean
Resource
是JDK提供的注解,默认注入方式为byName
。
1 |
|
Bean的作用域有哪些
Spring 中 Bean 的作用域通常有下面几种:
- singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续
getBean()
两次,得到的是不同的 Bean 实例。 - request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
- application/global-session (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
- websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
什么是AOP
AOP (Aspect-Oriented Programming: 面向切面编程) 能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
什么是MVC
MVC 是模型 (Model)、视图 (View)、控制器 (Controller) 的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
Spring MVC 下我们一般把后端项目分为 Service 层(处理业务)、Dao 层(数据库操作)、Pojo 层(实体类)、Controller 层 (控制层,返回数据给前台页面)
Spring MVC的核心组件
DispatcherServlet
:核心的中央处理器,负责接收请求、分发,并给予客户端响应。HandlerMapping
:处理器映射器,根据 uri 去匹配查找能处理的Handler
,并会将请求涉及到的拦截器和Handler
一起封装。HandlerAdapter
:处理器适配器,根据HandlerMapping
找到的Handler
,适配执行对应的Handler
;Handler
:请求处理器,处理实际请求的处理器。ViewResolver
:视图解析器,根据Handler
返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给DispatcherServlet
响应客户端
流程处理
- 客户端(浏览器)发送请求,
DispatcherServlet
拦截请求。 DispatcherServlet
根据请求信息调用HandlerMapping
。HandlerMapping
根据 uri 去匹配查找能处理的Handler
(也就是我们平常说的Controller
控制器) ,并会将请求涉及到的拦截器和Handler
一起封装。DispatcherServlet
调用HandlerAdapter
适配执行Handler
。Handler
完成对用户请求的处理后,会返回一个ModelAndView
对象给DispatcherServlet
,ModelAndView
顾名思义,包含了数据模型以及相应的视图的信息。Model
是返回的数据对象,View
是个逻辑上的View
。ViewResolver
会根据逻辑View
查找实际的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)
Spring中用到了哪些设计模式
- 工厂设计模式 : Spring 使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 - 代理设计模式 : Spring AOP 功能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 - 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 : Spring AOP 的增强或通知 (Advice) 使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。
Spring事务中的事务传播行为
事务传播行为是为了解决业务层方法之间互相调用的事务问题。
1 |
|
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
TransactionDefinition.PROPAGATION_REQUIRED
:使用的最多的一个事务传播行为,我们平时经常使用的@Transactional
注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。TransactionDefinitioin.PROPAGATION_REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则把当前事务挂起。_NESTED
:如果当前没有事务,则创建一个新的事务;否则创建一个事务作为当前事务的嵌套事务来运行_MANDATORY
:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
Spring事务的隔离级别
一共有五种隔离级别
ISOLATION_DEFAULT
:使用后端数据库默认的隔离级别。MySQL是可重复读,Oracle是读取已提交_READ_UNCOMMITED
:读取未提交,可能导致脏读、幻读、不可重复读_READ_COMMITED
:读取已提交,可能导致幻读和不可重复读_REPEATABLE_READ
:可能导致幻读_SERIALIZABLE
:完全服从ACID的隔离级别
Transactional注解的rollbackFor
在 @Transactional
注解中如果不配置 rollbackFor
属性,那么事务只会在遇到 RuntimeException
的时候才会回滚,加上 rollbackFor=Exception.class
, 可以让事务在遇到非运行时异常时也回滚。
Spring Security有哪些控制请求访问权限的方法
permitAll()
:无条件允许任何形式访问,不管你登录还是没有登录。anonymous()
:允许匿名访问,也就是没有登录才可以访问。denyAll()
:无条件决绝任何形式的访问。authenticated()
:只允许已认证的用户访问。fullyAuthenticated()
:只允许已经登录或者通过 remember-me 登录的用户访问。hasRole(String)
: 只允许指定的角色访问。hasAnyRole(String)
: 指定一个或者多个角色,满足其一的用户即可访问。hasAuthority(String)
:只允许具有指定权限的用户访问hasAnyAuthority(String)
:指定一个或者多个权限,满足其一的用户即可访问。hasIpAddress(String)
: 只允许指定 ip 的用户访问
如何对密码加密
这些加密算法实现类的父类是PasswordEncoder
,如果想要自己实现一个加密算法的话,也需要继承PasswordEncoder
。这个接口一共有3个必须实现的方法。
1 | public interface PasswordEncoder { |
官方推荐使用基于 bcrypt 强哈希函数的加密算法实现类。
介绍一下SpringBootApplication注解/SpringBoot的自动配置是如何实现的
SpringBootApplication可以看作是@Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
- 第一个是允许在上下文中注册额外的bean或导入其他配置类
- 第二个是启动SpringBoot的自动配置机制
- 第三个是扫描被
@Component(@Service,@Controller)
注解的bean,注解默认会扫描该类所在的包下所有的类
第二个注解是启动自动配置的关键。
- 引入Starter组件
- SpringBoot基于约定去Starter组件的路径下去找配置类
- SpringBoot使用ImportSelector去导入这些配置类,并根据@Conditional动态加载配置类里面的Bean到容器
常用注解
Spring Bean相关:
- @Autowired:自动导入对象到类中,被注入进的类同样要被Spring容器管理
- @RestController:该注解是@Controller和@ResponseBody的合集,表示这是个控制器bean。并且是将函数的返回值直接填入HTTP响应体中,是REST风格的控制器
- @Component:通用的注解。如果一个Bean不知道属于哪个层,可以使用@Component注解
- @Repository:对应Dao层,主要用于数据库相关操作
- @Service:对应服务层,涉及业务逻辑
- @Controller:接收用户请求并调用Service层返回数据给前段页面
HTTP请求相关:
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
前后端传值:
- @RequestParam:获取查询参数
- @Pathvariable:获取路径参数
- @RequestBody:用于读取Request的body 部分,并且Content-Type为
applicatioin/json
格式的数据,接收到数据之后会自动将数据绑定到Java对象上去。
参考文章:JavaGuide