IOC

IOC就是控制反转。也就是把创建对象管理对象等事情交给spring容器来做。
举例:传统的开发就是A依赖于B,那就是A手动new一个对象出来;springIOC就是spring来帮我们实例化对象,我们需要什么对象直接在spring容器里取出来就是了。

用一个技术就要看解决了什么问题,优点。而IOC的优点是解决了对象之间的耦合性,不会牵一发而动全身。
举例:service依赖dao层
无IOC:每次使用dao层实现类的增删改查就需要new这个实现类,如果有新的实现代码还要改业务代码。
有IOC:spring的配置时代就改配置的对应实现类就行,springboot的注解时代就是Qualifier注解注明就行。

AOP

AOP就是面向切面编程。就是把横切的地方从核心业务中分离出来,也是一种解耦。
通知就是在哪里触发,切面就是对关注点封装的类。

解决什么问题,优点。可以解耦日志通知,接口限流,事务管理,如果一直重复实现这些行为,代码会特别冗余,难以维护。

Bean的注入

依赖注入常见三种方式:

  1. 构造函数注入
  2. Setter注入
  3. Field(字段) 注入:在类的字段上使用注解(如 @Autowired 或 @Resource)来注入依赖项。

Bean的实现

  1. xml:标签和工厂标签
  2. Java配置类:@Configuration+@Bean手动创建bean逻辑
  3. 注解:@Component、@Repository、@Service等
    xml 和 java配置类 使用场景在于是第三方的SDK、第三方Jar包,不能自己写注解修改的这种场景
    注解自然就是自己写的业务代码的逻辑可以用的,同时也是自动装配机制的一环。

自动装配原理

自动装配就是现在的注解时代的不用写xml文件的核心机制。

那这个机制是通过 @SpringBootApplication启动的,而这个注解是三个注解集合:@Configuration@EnableAutoConfiguration@ComponentScan

  • @Configuration: 就是代表配置类,允许在上下文中注册额外的 Bean 或导入其他配置类。
  • @EnableAutoConfiguration: 启用 Spring Boot 的自动配置机制。它是自动配置的核心,允许 Spring Boot 根据项目的依赖和配置自动配置 Spring 应用的各个部分。
  • @ComponentScan:启用组件扫描。描被 @Component(以及 @Service、@Controller 等)注解的类,并将这些类注册为 Spring 容器中的 Bean。默认情况下,它会扫描该类所在包及其子包下的所有类。

EnableAutoConfiguration是核心,下面有两个核心注解:

  1. @AutoConfigurationPackage,该注解上有一个注解,其中 Registrar 的作用是将启动类所在包下的所有子包的组件扫描注入到spring容器中。这也是为什么在spring boot中,把项目的controller、pojo、service、dao等包放在启动类同级目录下的原因。
  2. @Import(AutoConfigurationImportSelector.class):这个注解的有一个方法的作用是去找配置文件,该方法去找META-INF/spring.factories文件中的所有自动配置类,并加载这些类。

    过程

    两条路,第一条路(手动配置的部分,也就是业务代码,有Component)

  3. 启动:@SpringBootApplication,标记启动类,开始激活装配
  4. 扫描:@ComponentScan+@AutoConfigurationPackage,扫描组件

    • (范围)@AutoConfigurationPackage:通过注解导入的Registrar类,注册启动类所在的包是基础包,也就是设置了一个默认的扫描最大范围
    • (执剑人)@ComponentScan:启动组件扫描器,扫描被@Component等注解修饰的类。

第二条路(自动配置的部分,去找springboot默认自动配置的配置文件配置,)

  1. 发现:@Import(AutoConfigurationImportSelector.class),发现配置清单(位于META-INF/spring.factories)
  2. 判断:配置清单上的每一个自动配置的类都会有一个 条件注解,用来判断需不需要装配,比如拿数据库举例子:
    判断两个事情:
    第一是判断有没有数据库的jar包,就是项目用没用数据库;
    第二是判断现在项目里有没有DataSource这个配置类,有说明不用自动装配了,已经在第一条路装配了。没有就需要自动装配。
  3. 注册:这步是把配置类内部的@Bean方法转化成BeanDefiniton注册到Spring容器里面 ----- 这些BeanDefiniton在生命周期里面实例化成Bean实例。

循环依赖问题

出现的原因:一个类初始化的时候需要另一个类的实例,反过来也是。

怎么解决提前暴露→在A实例化完但是还没依赖注入(属性填充)的时候,直接把A暴露出来给B用

IOC容器里面维护了三个Map存储不同阶段的Bean实例

Map名称存储内容作用
一级缓存singletonObjects存储完整、初始化完毕的单例Bean。(bean)正常的Bean容器。
二级缓存earlySingletonObjects存储提前暴露的Bean实例,可能是代理对象或原始对象。(Bean)存放已暴露但尚未完全初始化的Bean。
三级缓存singletonFactories存储一个工厂对象 (逻辑)负责判断要不要代理并且返回给二级缓存实例

最开始都在三级。进到a和b开始循环依赖的时候,a会判断需不需要AOP代理,需不需要a都会去二级,然后b就能拿到这个半成品的a,完成初始化。死锁就解开了。

不能解决的情况:构造器互相注入的;原型模式的bean。

前者不能的原因是通过构造函数注入就意味着这时候**实例化和注入是一个步骤**,因为在java中创建对象唯一的起点就是调用构造函数,调用之后就是实例化,而不能整出来一个空壳。
解决方法是**setter注入、注解注入**
后者不能的原因是三级缓存这个机制只给**单例模式**用。
解决方法是**改成单例 或 手动模拟三级机制**