在SpringBoot的启动引导调用run()会返回ApplicationContext这个Spring核心容器。
查看ApplicationContext的类图。
看到ApplicationContext继承了BeanFactory,且在此基础上实现了其他功能的扩展。但Spring最核心的容器还是BeanFactory,用来管理bean,实现控制反转(IOC)等功能。
首先需要明确,BeanFactory要创建bean,得先知道bean的类型是什么,模式是单例还是多例。也就是注册bean的概念!
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
现在我们只需要在类上写一个注解,标着该类需要注册到Spring容器,那Spring是怎么做到扫描标注有@Configuration与@Bean等注释的类,并且交给BeanFactory来管理的?
实际上BeanFactory本身是没有扫描,这些能力的,这些能力都是BeanFactory的后处理器赋予的。 怎么理解后处理器这个概念?
考虑模板方法设计模式。指完成一件事有固定的流程,比如一般技术面试有三轮,两轮技术面试和一轮hr面试,这就是固定的流程。在这个固定的流程上,有时候要加面一轮等,这就是后处理器。 除了BeanFactory有后处理器,Bean也有后处理器。这些后处理给原本的类做了功能增强的作用!
回到这里,BeanFactory扫描注解的能力是通过调用工具类赋予的。
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
这个方法会将下面的后处理器赋能给BeanFactory。
其中标红的就是扫描@Configuration注解的后处理器。
通过注册,注释@Configuration与@Bean标注的bean就会被交给Spring的容器管理。
但是这样还不够,在Bean内部,使用@Autowired与@Resource标注注入Bean。
需要绑定后处理器才能在Bean的生命周期实现依赖注入。
// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
上面的方法就是将已经在BeanFactory的后处理器,告诉BeanFactory,说明后处理器是用来处理Bean生命周期的依赖注入的。 附:Bean的生命周期
@Component
public class LifeCycleBean {
private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);
public LifeCycleBean() {
log.debug("构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) {
log.debug("依赖注入: {}", home);
}
@PostConstruct
public void init() {
log.debug("初始化");
}
@PreDestroy
public void destroy() {
log.debug("销毁");
}
}