Spring(1)-BeanFactory与Bean的注册和注入

198 阅读2分钟

在SpringBoot的启动引导调用run()会返回ApplicationContext这个Spring核心容器。 image.png 查看ApplicationContext的类图。 image.png 看到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来管理的? image.png

实际上BeanFactory本身是没有扫描,这些能力的,这些能力都是BeanFactory的后处理器赋予的。 怎么理解后处理器这个概念?

考虑模板方法设计模式。指完成一件事有固定的流程,比如一般技术面试有三轮,两轮技术面试和一轮hr面试,这就是固定的流程。在这个固定的流程上,有时候要加面一轮等,这就是后处理器。 除了BeanFactory有后处理器,Bean也有后处理器。这些后处理给原本的类做了功能增强的作用!

回到这里,BeanFactory扫描注解的能力是通过调用工具类赋予的。

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

这个方法会将下面的后处理器赋能给BeanFactory。

image.png

其中标红的就是扫描@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("销毁");
    }
}