spring.md 8.8 KB

什么是spring

Spring 是一款开源的轻量级 Java 开发框架,它使创建 Java 企业应用程序变得容易。它提供了在企业环境中使用 Java 语言所需的一切,并可以根据应用程序的需求灵活地创建多种架构。

Spring 提供的核心功能主要是 IoC 和 AOP

Spring IoC

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。

为什么叫控制反转?

  • 控制:指的是对象创建(实例化、管理)的权力
  • 反转:控制权交给外部环境(Spring 框架、IoC 容器)

依赖查找和依赖注入的区别是什么?

  • 依赖查找:主动查找依赖的方式。依赖查找的对象包含spring beandefinition以及单例对象
  • 依赖注入:spring容易自动依赖绑定的方式。依赖注入还包含Resolvable Dependency以及@value对象

Spring Bean 作用域

作用域 说明
singleton 默认 Spring Bean 作用域,一个 BeanFactory 有且仅有一个实例
prototype 原型作用域,每次依赖查找和依赖注入生成新 Bean 对象
request 将 Spring Bean 存储在 ServletRequest 上下文中
session 将 Spring Bean 存储在 HttpSession 中
application 将 Spring Bean 存储在 ServletContext 中

@Autowired@Resource 的区别是什么?

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

Bean 是线程安全的吗?

Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。

大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:

  1. 在 Bean 中尽量避免定义可变的成员变量。
  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

Spring Boot自动装配原理

  1. 在Spring Boot项目中有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装:@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan 其中@EnableAutoConfiguration是实现自动化配置的核心注解。
  2. 该注解通过@Import注解导入AutoConfigurationImportSelector,这个类实现了一个导入器接口ImportSelector。在该接口中存在一个方法selectImports
  3. 该方法的返回值是一个数组,数组中存储的就是要被导入到spring容器中的类的全类名。在AutoConfigurationImportSelector类中重写了这个方法,
  4. 该方法内部就是读取了项目的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。
  5. 在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。

springboot三个注解

@SpringBootConfiguration

在这里插入图片描述

  • 它是JavaConfig形式的基于Spring IOC容器的配置类使用的一种注解。SpringBoot本质上就是一个Spring应用,通过这个注解来加载IOC容器的配置。所以在启动类里面标注了@Configuration,意味着它也是一个IOC容器的配置类

@ComponentScan

  • 作用:扫描主配置类包的所有包下的类,相当于xml配置文件中的context:component-scan。eg:pojo中的User类

@EnableAutoConfiguration(重点!!!)

在这里插入图片描述

  1. @AutoConfigurationPackage:自动配置包
  • 作用:给Spring容器中导入一个Registrar注册器组件

@AutoConfigurationPackage@ComponentScan一样,都是将Spring Boot启动类所在的包及其子包里面的组件扫描到IOC容器中,但是区别是@AutoConfigurationPackage扫描@Enitity、@Mapper等第三方依赖的注解,@ComponentScan只扫描@Controller/@Service/@Component/@Repository这些常见注解。所以这两个注解扫描的对象是不一样的。当然这只是直观上的区别,更深层次说,@AutoConfigurationPackage是自动配置的提醒,是Spring Boot中注解,而@ComponentScan是Spring的注解

  1. @Import(AutoConfigurationImportSelector.class)——核心注解
  • 该注解通过@Import注解导入AutoConfigurationImportSelector,这个类实现了一个导入器接口ImportSelector。在该接口中存在一个方法selectImports
  • 通过与BeanClassLoaderAware结合注入bean

SpringBoot启动流程

  • 首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象
  • 进入run()方法,创建应用监听器SpringApplicationRunListeners开始监听
  • 然后加载SpringBoot配置环境(ConfigurableEnvironment),然后把配置环境(Environment)加入监听对象中
  • 然后加载应用上下文(ConfigurableApplicationContext),当做run方法的返回对象
  • 最后创建Spring容器,refreshContext(context),实现starter自动化配置和bean的实例化等工作。

autowired变量都是单例的吗?

默认都是单例对象,就算对象标注@Scope(value = “prototype”)也无法生效

特殊情况是多例对象,当注入方和被注入方都被@Scope(value = “prototype”)标注才会使多例

bean生命周期

  • BeanDefinition 注册阶段 - registerBeanDefinition
  • BeanDefinition 合并阶段 - getMergedBeanDefinition
  • Bean 实例化前阶段 - resolveBeforeInstantiation
  • Bean 实例化阶段 - createBeanInstance
  • Bean 实例化后阶段 - populateBean
  • Bean 属性赋值阶段 - populateBean
  • Bean Aware 接口回调阶段 - initializeBean
  • Bean 初始化前阶段 - initializeBean
  • Bean 初始化阶段 - initializeBean
  • Bean 初始化后阶段 - initializeBean
  • Bean 初始化完成阶段 - preInstantiateSingletons
  • Bean 销毁前阶段 - destroyBean
  • Bean 销毁阶段 - destroyBean

AOP

AOP(Aspect-Oriented Programming:面向切面编程)

AOP 切面编程设计到的一些专业术语:

术语 含义
目标(Target) 被通知的对象
代理(Proxy) 向目标对象应用通知之后创建的代理对象
连接点(JoinPoint) 目标对象的所属类中,定义的所有方法均为连接点
切入点(Pointcut) 被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
通知(Advice) 增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情
切面(Aspect) 切入点(Pointcut)+通知(Advice)
Weaving(织入) 将通知应用到目标对象,进而生成代理对象的过程动作

AOP流程

  1. 创建Advice

一个advice就是一个方法,即目标对象必须要执行的完成的工作。

因为spring aop只能代理目标方法,所有advice就会被解析成MethodAdvice

这里以BeforeAdvice举例。

  1. 创建Interceptor

MethodBeforeAdvice,但只有这个类还不够,因为我们的方法还无法继续往下执行,需要将MethodBeforeAdvice转化为methodInterceptor。它封装了MethodBeforeAdvice,将其变成真正的增强方法,因为methodInterceptor封装了代理方法,提供了统一的逻辑。

  1. 创建Advisor

一个advisor对应一个pointcut和一个advice。