Springboot自动装配原理
在Spring Boot中,Spring Framework的IoC容器会自动扫描注解了@Component、@Service、@Repository和@Controller的类,并将它们作为Bean加入到应用上下文中。这些Bean可以在其他Bean中作为依赖注入。
实际上,SpringBoot在底层使用了一个名为BeanDefinition的东西来管理这些Bean的定义,这个BeanDefinition可以理解为一个Bean的模板,它描述了Bean的类型、作用域、是否懒加载等信息。当Spring容器启动时,它会读取这些BeanDefinition,并创建对应的Bean实例。这些Bean的信息会被保存在一个Map结构中,这个Map被称为BeanDefinitionMap。这个Map用来存储所有通过注解方式声明的Bean的定义,以便之后可以创建和管理这些Bean。这个过程是自动的,通常不需要用户干预。但如果你需要自定义Bean的创建过程,你可能需要直接操作这个BeanDefinitionMap。这通常是在创建基于代理的IoC容器时发生的,或者是在需要动态注册Bean的场景中发生的。
如果你需要查看这个Map中的内容,你可以通过实现ApplicationContextAware接口,然后访问ApplicationContext的beanFactory属性,进而访问BeanDefinitionMap。但这通常不是推荐的做法,因为这会破坏Spring的封装性,并可能导致代码与Spring的版本耦合。
Springboot自动装配非常简单,仅仅需要在启动类上添加@SpringBootApplication注解即可。 @SpringBootApplication是一个组合注解是@SpringBootConfiguration+@EnableAutoConfiguration+@ComponentScan 三个注解的组合。
下来我们通过一个例子理解:
项目结构图如下:

1).设计CaculationStrategy接口
package com.simoniu.spt.course.service;
public interface CaculationStrategy {
int operate(int num1,int num2);
}
2).分别设计add/sub/multi/divid四个实现了CaculationStrategy 接口的实现类。
//AddCaculationStrategyImpl.java
@Component("add")
public class AddCaculationStrategyImpl implements CaculationStrategy {
@Override
public int operate(int num1, int num2) {
return num1+num2;
}
}
//SubtractionStrategyImpl.java
@Component("sub")
public class SubtractionStrategyImpl implements CaculationStrategy {
@Override
public int operate(int num1, int num2) {
return num1-num2;
}
}
//MultipleStrategyImpl.java
@Component("multi")
public class MultipleStrategyImpl implements CaculationStrategy {
@Override
public int operate(int num1, int num2) {
return num1*num2;
}
}
//DividStrategyImpl.java
@Component("divid")
public class DividStrategyImpl implements CaculationStrategy {
@Override
public int operate(int num1, int num2) {
return num1/num2;
}
}
3).使用策略模式实现bean自动注入,通过工厂类实现。
import com.google.common.collect.Maps;
import com.simoniu.spt.course.service.CaculationStrategy;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class CaculationFactory {
public final Map<String, CaculationStrategy> caculationStrategyMap= Maps.newHashMapWithExpectedSize(4);
public CaculationFactory(Map<String, CaculationStrategy> strategyMap){
System.out.println("-----strategyMap-----");
System.out.println(strategyMap);
this.caculationStrategyMap.clear();
this.caculationStrategyMap.putAll(strategyMap);
}
public Map<String, CaculationStrategy> getCaculationStrategyMap() {
return caculationStrategyMap;
}
}
Guava是对Java API的补充,可以理解为是java的工具类,对Java开发中常用功能进行更优雅的实现,使得编码更加轻松,代码容易理解。需要在pom.xml添加以下依赖。
<properties>
...
<guava.version>30.1-jre</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version> <!-- 请使用最新的稳定版本 -->
</dependency>
</dependencies>
4).设计服务层
import com.simoniu.spt.course.factory.CaculationFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
public class CaculationService {
@Autowired
private CaculationFactory caculationFactory;
public int operateByStrategy(String strategy,int num1,int num2){
return caculationFactory.getCaculationStrategyMap().get(strategy).operate(num1,num2);
}
}
5).controller测试自动装配
import com.simoniu.spt.course.service.CaculationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/strategy")
public class TestStrategyController {
@Autowired
private CaculationService caculationService;
@GetMapping("/test/{operation}/{num1}/{num2}")
public int testCaculation(@PathVariable String operation,@PathVariable int num1, @PathVariable int num2){
return caculationService.operateByStrategy(operation,num1,num2);
}
}
启动项目,我们发现add,sub,multi,divid自已经注入到IOC容器,其数据类型就是Map数据类型。
-----strategyMap-----
{add=com.simoniu.spt.course.service.impl.AddCaculationStrategyImpl@3d07df3f, divid=com.simoniu.spt.course.service.impl.DividStrategyImpl@714da74, multi=com.simoniu.spt.course.service.impl.MultipleStrategyImpl@60eeb633, sub=com.simoniu.spt.course.service.impl.SubtractionStrategyImpl@4b010b3f}
测试一个加法运算接口。
