Spring

173 阅读6分钟

1、Spring核心

1.1、控制反转(IOC)

控制反转就是把创建对象的权利交给框架去控制,而不需要人为地去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。

1.2、依赖注入(DI)

  • 依赖注入是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。
  • 依赖注入提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
  • 依赖注入是控制反转实现的手段和方法。

1.3、常见的注入方式

  1. setter方法注入
public class UserController {
    // 注入 UserService 对象
    private UserService userService;
    public void setUserService(UserService userService){
        this.userService = userService;
    }
}
  1. 构造器注入(推荐使用)
public class UserController {
    private UserService userService;
    public UserController(UserService userService){
        this.userService = userService;
    }
}
  1. 注解注入
public class UserController {
    // 使用注解自动注入
    @Autowired()
    private UserService userService;
    
}

2、AOP(面向切面编程)

特点:

  1. 降低模块之间的耦合度
  2. 使系统容易扩展
  3. 更好的代码复用。

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 有什么区别?

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

4、Spring 中 bean 的作用域有几种类型?

  1. 单例(Singleton):整个应用程序,只创建 bean 的一个实例(Spring默认);
  2. 原型(Prototype):每次注入都会创建一个新的 bean 实例;
  3. 会话(Session):每个会话创建一个 bean 实例,只在 Web 系统中有效;
  4. 请求(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的区别

  1. Spring Framework 简称 Spring,是整个 Spring 生态的基础。
  2. SpringMVC是一种web层的MVC框架,用来构建web应用。
  3. SpringBoot 我理解就是把常用的基础框架组合起来

8、Spring、SpringBoot、SpringCloud 的区别是什么?

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