1、Spring核心
1.1、控制反转(IOC)
控制反转就是把创建对象的权利交给框架去控制,而不需要人为地去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。
1.2、依赖注入(DI)
- 依赖注入是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。
- 依赖注入提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
- 依赖注入是控制反转实现的手段和方法。
1.3、常见的注入方式
- setter方法注入
public class UserController {
// 注入 UserService 对象
private UserService userService;
public void setUserService(UserService userService){
this.userService = userService;
}
}
- 构造器注入(推荐使用)
public class UserController {
private UserService userService;
public UserController(UserService userService){
this.userService = userService;
}
}
- 注解注入
public class UserController {
// 使用注解自动注入
@Autowired()
private UserService userService;
}
2、AOP(面向切面编程)
特点:
- 降低模块之间的耦合度
- 使系统容易扩展
- 更好的代码复用。
2.1、AspectJ中注解说明
- @Before — 前置通知,在连接点方法前调用;
- @Around — 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法;
- @After — 后置通知,在连接点方法后调用;
- @AfterReturning — 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常;
- @AfterThrowing — 异常通知,当连接点方法异常时调用。
2.2、动态代理
JDK 原生提供的动态代理就是通过反射实现的,但动态代理的实现方式还可以是cglib(基于 ASM)等,并不局限于反射。
2.2.1、JDK原生动态代理
JDK Proxy 只能代理实现接口的类(即使是 extends 继承类也是不可以代理的),通过实现 InvocationHandler接口进行实现。 cglib 的调用通过实现 MethodInterceptor 接口的intercept 方法,调用 invokeSuper 进行动态代理的。它可以直接对普通类进行动态代理,并不需要像 JDK 代理那样,需要通过接口来完成,值得一提的是 Spring的动态代理也是通过 cglib 实现的。
3、@Component 和 @Bean 有什么区别?
- @Component 作用于类,而 @Bean 注解作用于方法。
- @Component 通常是通过类路径扫描来自动侦测和装配对象到 Spring 容器中,比如 @ComponentScan 注解就是定义扫描路径中的类装配到 Spring 的 Bean容器中;@Bean 注解是告诉 Spring 这是某个类的实例,当我需要用它的时把它给我,@Bean 注解比 @Component 注解自定义性更强,很多地方我们只能通过@Bean 注解来注册 Bean,比如当我们引用第三方库中的类需要装配到 Spring 容器时,则只能通过 @Bean 来实现。
4、Spring 中 bean 的作用域有几种类型?
- 单例(Singleton):整个应用程序,只创建 bean 的一个实例(Spring默认);
- 原型(Prototype):每次注入都会创建一个新的 bean 实例;
- 会话(Session):每个会话创建一个 bean 实例,只在 Web 系统中有效;
- 请求(Request):每个请求创建一个 bean 实例,只在 Web 系统中有效。
5、@Transaction注解
5.1、添加位置
- 接口实现类或接口实现方法上,而不是接口类中。
- @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。系统设计:将标签放置在需要进行事务管理的方法上,而不是放在所有接口实现类上:只读的接口就不需要事务管理,由于配置了@Transactional就需要AOP拦截及事务的处理,可能影响系统性能。
5.2、@Transaction注解原理
@Transactional 实质是使用了 JDBC 的事务来进行事务控制的 @Transactional 基于 Spring 的动态代理的机制
@Transactional 实现原理:
1) 事务开始时,通过AOP机制,生成一个代理connection对象,
并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。
在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库,
执行所有数据库命令。
[不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚]
(物理连接 connection 逻辑上新建一个会话session;
DataSource 与 TransactionManager 配置相同的数据源)
2) 事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,
然后关闭该代理 connection 对象。
(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)
5.3、事务传播行为
如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
1. TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3. TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
5. TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
6. TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
7. TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
6、Spring 中的 Bean 是线程安全的吗?
Spring 中的 Bean 默认是单例模式,Spring 框架并没有对单例 Bean 进行多线程的封装处理,因此默认的情况 Bean 并非是安全的,最简单保证 Bean 安全的举措就是设置 Bean 的作用域为 Prototype(原型)模式,这样每次请求都会新建一个 Bean。
7、Spring、SpringMVC和Springboot的区别
- Spring Framework 简称 Spring,是整个 Spring 生态的基础。
- SpringMVC是一种web层的MVC框架,用来构建web应用。
- SpringBoot 我理解就是把常用的基础框架组合起来
8、Spring、SpringBoot、SpringCloud 的区别是什么?
- Spring Framework 简称 Spring,是整个 Spring 生态的基础。
- Spring Boot 是一个快速开发框架,让开发者可以迅速搭建一套基于Spring 的应用程序,并且将常用的 Spring 模块以及第三方模块,如MyBatis、Hibernate 等都做了很好的集成,只需要简单的配置即可使用,不需要任何的 XML 配置文件,真正做到了开箱即用,同时默认支持 JSON格式的数据,使用 Spring Boot 进行前后端分离开发也非常便捷。
- Spring Cloud 是一套整合了分布式应用常用模块的框架,使得开发者可以快速实现微服务应用。作为目前非常热门的技术,有关微服务的话题总是在各种场景下被大家讨论,企业的招聘信息中也越来越多地出现对于微服务架构能力的要求。