第一章 容器与Bean

容器与Bean

1. 容器接口

1.1 什么是 BeanFactory

  • 它是 ApplicationContext 的父接口
  • 它才是 Spring 的核心容器,主要的 ApplicationContext 实现组合了它的功能,也就是说,BeanFactoryApplicationContext 中的一个成员变量。

常用的 context.getBean("xxx") 方法,其实是调用了 BeanFactorygetBean() 方法。

1.2 BeanFactory 能做什么?

进入 BeanFactory 接口,在 IDEA 中使用快捷键 Ctrl + F12 查看这个接口中所有的方法定义:

image-20241228211746149

可以看到,虽然 BeanFactory 表面上只有 getBean() 方法,但是实际上 Spring 中的控制反转依赖注入生命周期中的各个功能都由它的实现类提供。

查看 DefaultListableBeanFactory 的类图,按住 Ctrl + Alt + uDefaultListableBeanFactory 实现了 BeanFactory 接口,

它能管理 Spring 容器中的所有 bean。

也包含单例的 bean 对象:

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.forEach((k, v) -> {
            logger.info("k: {}, v: {}", k, v);
        });
    }
}

image-20241228212139416

上面的单例的对象是通过反射拿到的,在类 DefaultSingletonBeanRegistry 里面:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

1.3 ApplicationContext 的功能

ApplicationContext 除了实现 BeanFactory 外,还继承了:

  • MessageSource:处理国际资源
  • ResourcePatternResolver:通过通配符进行资源匹配
  • EnvironmentCapable:读取 Spring 环境信息、配置信息
  • ApplicationEventPublisher:使其具备发布事件的功能

MessageResource 的使用

resources 目录下创建资源文件:

image-20241228213922296

内容分别是:

# messages_en.properties
hi=hi
# messages_zh.properties
hi=你好

在main函数中:

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        logger.info(context.getMessage("hi", null, Locale.ENGLISH));
        logger.info(context.getMessage("hi", null, Locale.CHINA));
        context.close();
    }
}

控制台输出

2024-12-28T21:41:43.127+08:00  INFO 29460 --- [           main] com.jie.demo01.Demo01Application         : hi
2024-12-28T21:41:43.129+08:00  INFO 29460 --- [           main] com.jie.demo01.Demo01Application         : 你好

ResourcePatternResolver 使用

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        Resource[] resources = context.getResources("classpath:application.yml");
        logger.info("resources: {}", resources);
        context.close();
    }
}

使用 classpath* 可以加载 jar 里类路径下的 resource

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        logger.info("resources: {}", resources);
        context.close();
    }
}

EnvironmentCapable 的使用

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        ConfigurableEnvironment environment = context.getEnvironment();
        logger.info(environment.getProperty("java_home"));
        logger.info(environment.getProperty("test.user.name"));
        context.close();
    }
}

输出:

2024-12-28T21:51:59.134+08:00  INFO 3444 --- [           main] com.jie.demo01.Demo01Application         : C:\dev\jdk\jdk-1.8
2024-12-28T21:51:59.135+08:00  INFO 3444 --- [           main] com.jie.demo01.Demo01Application         : test

其中,“java_home” 是从环境变量中读取,“test.user.name” 是从 application.yml 文件中读取。

ApplicationEventPublisher 使用

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(Demo01Application.class, args);
        context.publishEvent(new Event(context));
        context.close();
    }

    static class Event extends ApplicationEvent {
        public Event(Object source) {
            super(source);
        }
    }

    @Component
    static class Listener {
        @EventListener
        public void on(Event event) {
            logger.info("event: {}", event);
        }
    }
}

输出:

2024-12-28T21:58:31.809+08:00  INFO 16796 --- [           main] com.jie.demo01.Demo01Application         : event: com.jie.demo01

就是事件的发布与监听。

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    public static void main(String[] args) throws Exception {
        // 定义 bean
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
                genericBeanDefinition(Config.class) // Bean 类型
                .setScope("singleton") // Bean 范围
                .getBeanDefinition();
        // 注册 bean
        beanFactory.registerBeanDefinition("config", configBeanDefinition);
        // 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            // 执行 BeanFactory 的后处理器
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        for (String name : beanFactory.getBeanDefinitionNames()) {
            logger.info("name:{}", name);
        }
    }

    @Configuration
    static class Config {
        public Config() {

        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {
        @Autowired
        private Bean2 bean2;

        public Bean1() {

        }

        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        public Bean2() {

        }
    }
}

2. 容器的实现

2.1 BeanFactory 的实现

现有如下类,尝试将 Config 添加到 Bean 工厂中:

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    public static void main(String[] args) throws Exception {
        // 定义 bean
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
                genericBeanDefinition(Config.class) // Bean 类型
                .setScope("singleton") // Bean 范围
                .getBeanDefinition();
        // 注册 bean
        beanFactory.registerBeanDefinition("config", configBeanDefinition);
        // 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            // 执行 BeanFactory 的后处理器
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        for (String name : beanFactory.getBeanDefinitionNames()) {
            logger.info("name:{}", name);
        }
    }

    @Configuration
    static class Config {
        public Config() {

        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {
        @Autowired
        private Bean2 bean2;

        public Bean1() {

        }

        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        public Bean2() {

        }
    }
}

输出:

22:19:25.854 [main] INFO com.jie.demo01.Demo01Application -- name:config
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.annotation.internalCommonAnnotationProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.event.internalEventListenerProcessor
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:org.springframework.context.event.internalEventListenerFactory
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:bean1
22:19:25.858 [main] INFO com.jie.demo01.Demo01Application -- name:bean2

BeanFactory 的后处理器主要是为了扩展 BeanFactory 的功能的,比如添加对 @Bean 注解的解析。

Bean 的处理器和 BeanFactory 是不一样的:

@SpringBootApplication
public class Demo01Application {

    private static final Logger logger = LoggerFactory.getLogger(Demo01Application.class);

    public static void main(String[] args) throws Exception {
        // 定义 bean
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder.
                genericBeanDefinition(Config.class) // Bean 类型
                .setScope("singleton") // Bean 范围
                .getBeanDefinition();
        // 注册 bean
        beanFactory.registerBeanDefinition("config", configBeanDefinition);
        // 给 BeanFactory 添加一些常用的后处理器,使得其可以解析类似 @Commpoent 等注解的功能
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            // 执行 BeanFactory 的后处理器
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        for (String name : beanFactory.getBeanDefinitionNames()) {
            logger.info("name:{}", name);
        }

        // Bean 后处理器 针对 bean 的每个生命周期的各个阶段提供扩展,例如 @Autowried @Resource
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach((
                beanPostProcessor -> beanFactory.addBeanPostProcessor(beanPostProcessor)));

        logger.info("beanFactory:{}", beanFactory);
        // 获取 bean
        Bean1 bean1 = beanFactory.getBean(Bean1.class);
        logger.info("bean1:{}", bean1);
        logger.info("bean2:{}", bean1.getBean2());
    }

    @Configuration
    static class Config {
        public Config() {

        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {
        @Autowired
        private Bean2 bean2;

        public Bean1() {

        }

        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        public Bean2() {

        }
    }
}

Bean 的处理器主要是扩展 Bean 生命周期中的一些功能的,比如 @Autowired @Resource

总结

BeanFactory 不会:

  • 主动调用 BeanFactory 后置处理器;
  • 主动初始化单例对象;
  • 主动添加 Bean 后置处理器;
  • 解析 ${} 和 #{}

BeanFactory 是一个基础的,很多功能没有加入进来。接下来介绍的 ApplicationContext 就包含了所有的功能。

2.2 ApplicationContext 的实现

以下xml配置方式的了解即可,现在基本不用了。

ClassPathXmlApplicationContext 使用

Bean1.java:

public class Bean1 {
    public Bean1() {

    }
}

Bean2.java:

public class Bean2 {

    private Bean1 bean1;

    public Bean2() {

    }

    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }

    public Bean1 getBean1() {
        return bean1;
    }
}

test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bean1" class="com.jie.demo01.beans.Bean1" />

    <bean id="bean2" class="com.jie.demo01.beans.Bean2">
        <property name="bean1" ref="bean1" />
    </bean>
</beans>

启动类:

@SpringBootApplication
public class Demo01Application {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
        System.out.println(context.getBean("bean2"));
        context.close();
    }
}

原理类似如下:

@SpringBootApplication
public class Demo01Application {
    public static void main(String[] args) throws Exception {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前的");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后的");
        // 读取xml文件的信息,放到beanFactory里面
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions("test.xml");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

通过 XmlBeanDefinitionReader 读取 xml 文件里面的信息,放到 beanFactory 里面。

输出:

读取之前的
读取之后的
bean1
bean2

AnnotationConfigApplicationContext 的使用

这是基于配置类实现 bean 对象的处理的:

定义 config 类:

@Configuration
public class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }
}

实现:

@SpringBootApplication
public class Demo01Application {
    public static void main(String[] args) throws Exception {
        
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

输出:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config
bean1
bean2

这种方式会把 config 类也加入到容器中。

AnnotationConfigServletWebApplicationContext 的使用

使用 AnnotationConfigServletWebApplicationContext 必须要实现三个 bean

@Configuration
public class WebConfig {
    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        // 返回服务器的工厂
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        // 控制器
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
        // 注册 dispatcherServlet 到 tomcat 服务器
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }

    @Bean("/hello")
    public Controller controller() {
        return (request, response) -> {
            response.getWriter().print("hello");
            return null;
        };
    }
}

其中写了一个测试用的controller。

启动类:

public class Demo01Application {
    public static void main(String[] args) throws Exception {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }
}

浏览器访问:localhost:8080/hello

image-20241228231417987

这里我们可以看出,内嵌Tomcat是如何工作的。

2.3 常见的 Bean 后处理器

bean 后处理器的作用:为 Bean 生命周期各个阶段提供扩展

AutowireAnnotationBeanPostProcessor 解析

执行依赖注入的源码:

    public void processInjection(Object bean) throws BeanCreationException {
        Class<?> clazz = bean.getClass();
        InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null);

        try {
            metadata.inject(bean, (String)null, (PropertyValues)null);
        } catch (BeanCreationException var5) {
            BeanCreationException ex = var5;
            throw ex;
        } catch (Throwable var6) {
            Throwable ex = var6;
            throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
        }
    }
	protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
            if (this.shouldInject(pvs)) {
                if (this.isField) {
                    Field field = (Field)this.member;
                    ReflectionUtils.makeAccessible(field);
                    field.set(target, this.getResourceToInject(target, requestingBeanName));
                } else {
                    try {
                        Method method = (Method)this.member;
                        ReflectionUtils.makeAccessible(method);
                        method.invoke(target, this.getResourceToInject(target, requestingBeanName));
                    } catch (InvocationTargetException var5) {
                        InvocationTargetException ex = var5;
                        throw ex.getTargetException();
                    }
                }
            }
        }

执行流程分析:

  • 首先调用 InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null); 找到加了 @Autowired @Value 注解的方法或者字段
  • 然后调用 metadata.inject(bean, (String)null, (PropertyValues)null); 通过反射注入
  • inject 方法中,判断需要注入的是方法还是字段,调用反射API

3. Aware 接口

3.1 Aware 接口

Aware 接口用来实现一些和容器相关的信息,比如:

  • BeanNameAware 注入 Bean 的名字
  • BeanFactoryAware 注入 BeanFactory 容器
  • ApplicationContextAware 注入 ApplicationContext 容器
  • EmbeddedValueResolverAware 解析 ${}
@Slf4j
public class MyBean implements BeanNameAware, ApplicationContextAware {

    @Override
    public void setBeanName(String name) {
        log.info("当前bean【{}】的名字是【{}】", this, name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("当前bean【{}】容器是【{}】", this, applicationContext);
    }
}
public class Demo03Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);

        context.refresh();
        context.close();
    }
}

输出:

13:07:46.510 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@782663d3】的名字是【myBean】
13:07:46.518 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@782663d3】容器是【org.springframework.context.support.GenericApplicationContext@22f71333, started on Sun Dec 29 13:07:46 CST 2024】

这些实现的方法会在 AbstractAutowireCapableBeanFactory 下的 invokeAwareMethods 调用:

	private void invokeAwareMethods(String beanName, Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                BeanNameAware beanNameAware = (BeanNameAware)bean;
                beanNameAware.setBeanName(beanName);
            }

            if (bean instanceof BeanClassLoaderAware) {
                BeanClassLoaderAware beanClassLoaderAware = (BeanClassLoaderAware)bean;
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    beanClassLoaderAware.setBeanClassLoader(bcl);
                }
            }

            if (bean instanceof BeanFactoryAware) {
                BeanFactoryAware beanFactoryAware = (BeanFactoryAware)bean;
                beanFactoryAware.setBeanFactory(this);
            }
        }

    }

3.2 InitializingBean

@Slf4j
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {

    @Override
    public void setBeanName(String name) {
        log.info("当前bean【{}】的名字是【{}】", this, name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("当前bean【{}】容器是【{}】", this, applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("当前bean【{}】初始化完成", this);
    }
}

输出:

13:16:54.196 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】的名字是【myBean】
13:16:54.206 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】容器是【org.springframework.context.support.GenericApplicationContext@35f983a6, started on Sun Dec 29 13:16:54 CST 2024】
13:16:54.206 [main] INFO com.jie.demo03.beans.MyBean -- 当前bean【com.jie.demo03.beans.MyBean@28ac3dc3】初始化完成

该方法会在 Aware 接口之后调用。

这个方法会在 AbstractAutowireCapableBeanFactory 下的 invokeInitMethods 调用:

    protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
 
            ((InitializingBean)bean).afterPropertiesSet(); // 调用方法
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String[] initMethodNames = mbd.getInitMethodNames();
            if (initMethodNames != null) {
                String[] var6 = initMethodNames;
                int var7 = initMethodNames.length;

                for(int var8 = 0; var8 < var7; ++var8) {
                    String initMethodName = var6[var8];
                    if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
                        this.invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
                    }
                }
            }
        }

    }

BeanFactoryAware ApplicationContextAware EmbeddedValueResolverAware 三个接口的功能可以使用 @Autowired 注解实现,InitializingBean 接口的功能也可以使用 @PostConstruct 注解实现,为什么还要使用接口呢?

@Autowired @PostConstruct 注解的解析需要使用 Bean 后置处理器,属于拓展功能,而这些接口属于内置功能,不加任何拓展 Spring 就能识别。在某些情况下,拓展功能会失效,而内容功能不会失效

3.3 @Autowired 失效

如下代码:

@Slf4j
@Configuration
public class MyConfig {
    
    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        log.info("注入 ApplicationContext");
    }

    @PostConstruct
    public void init() {
        log.info("初始化");
    }
    
    @Bean
    public BeanFactoryPostProcessor processor1() {
        return processor -> log.info("执行 processor1");
    }
}
public class Demo03Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myConfig", MyConfig.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        // 解析配置类中的注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();
        context.close();
    }
}

输出:

13:29:43.666 [main] INFO com.jie.demo03.beans.MyConfig -- 执行 processor1

可以看见,@Autowired 失效了,但是 processor1() 方法却没有。

为什么?

对于 context.refresh(); 方法来说,它主要按照以下顺序干了三件事:

  • 执行 BeanFactory 后置处理器;
  • 添加 Bean 后置处理器;
  • 创建和初始化单例对象。

当 Java 配置类中定义了 BeanFactoryPostProcessor 时,如果要创建配置类中的 BeanFactoryPostProcessor 就必须提前创建和初始化 Java 配置类。

在创建配置类时,由于 BeanPostProcessor 还没配置好,这时候就不能解析 @Autowired 注解,导致注解失效。

要解决这个问题也很简单,使用相关接口的功能实现注入和初始化:

@Slf4j
@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("注入 ApplicationContext");
    }

    @Bean
    public BeanFactoryPostProcessor processor2() {
        return processor -> log.info("执行 processor2");
    }
}

3.4 总结

  1. Aware 接口提供了一种 内置 的注入手段,可以注入BeanFactoryApplicationContext
  2. InitializingBean 接口提供了一种内置的初始化手段;
  3. 内置的注入和初始化不受拓展功能的影响,总会被执行,因此 Spring 框架内部的类总是使用这些接口。

喜欢的点个关注,博客链接:何事秋风悲画扇,另外有想一起做项目的给个留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值