Spring IoC 容器

本文关键词:IoC容器、BeanFactory、ApplicationContext、扩展点、生命周期

什么是 IOC 容器

Spring IoC 容器可以读取配置文件中描述的 Bean 之间的关系,利用 Java 反射机制实例化这些 Bean,并管理这些类,提供 Bean 实例缓存、生命周期管理、Bean 实力代理、事件发布、资源装载等高级服务。

通俗的来说,IOC容器是指的 Spring Bean 工厂里面 Map 存储结构。

Spring启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的 Bean 配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。

Bean 配置信息是 Bean 的元数据信息,它由以下4个方面组成:

  • Bean 的实现类
  • Bean 的属性信息,如数据源的连接数、用户名、密码等
  • Bean 的依赖关系,Spring 根据依赖关系配置完成 Bean 之间的装配
  • Bean 的行为配置,如生命周期范围及生命周期各过程的回调函数等

Bean 元数据信息在 Spring 容器中的内部对应物是由一个个 BeanDefinition形成的 Bean 注册表:

Bean 与容器的关系
Bean 与容器的关系

BeanFactory 是 Spring 框架最核心的接口,它提供了高级 IoC 的配置机制。BeanFactory 中最重要的 getBean(String beanName) 方法可以从 IoC 容器中获取指定 BeanName 的 Bean。BeanFactory 作为 IoC 容器的顶层接口,其功能是通过其他实现类来得到扩展的。BeanFactory 和相关接口(如BeanFactoryAware、InitializingBean、DisposableBean)是其他框架组件的重要集成点。

BeanFactory 使管理不同类型的 Java 对象成为可能,ApplicationFactory 建立在 BeanFactory 基础上,提供了更多面向应用的功能,提供了国际化支持和框架事件体系,更易于创建实际应用。我们一般称 BeanFactory 为 IoC 容器,而称 ApplicationContext 为应用上下文。

对于二者的用途,我们可以进行简单的划分 BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都可以直接使用 ApplicationContext 而非底层的 BeanFactory。

二者的详细对比:

特性BeanFactoryApplicationContext
Bean 实例化/装载YesYes
自动 BeanPostProcessor 注册NoYes
自动 BeanFactoryPostProcessor 注册NoYes
国际化NoYes
ApplicationEvent 发布NoYes

①BeanFactroy 采用的是延迟加载形式来注入Bean 的,即只有在使用到某个 Bean 时 (调用getBean()),才对该 Bean 进行加载实例化。这样,我们就不能发现一些存在的 Spring 的配置问题。如果 Bean 的某一个属性没有注入,BeanFacotry 加载后,直至第一次使用调用 getBean 方法才会抛出异常。

②ApplicationContext,它是在容器启动时,一次性创建了所有的 Bean。这样,在容器启动时,我们就可以发现 Spring 中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext 启动后预载入所有的单实例 Bean,通过预载入单实例 bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。它还可以为 Bean 配置 lazy-init=true 来让 Bean 延迟实例化;

③相对于基本的 BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

SpringBean 的生命周期

概览

什么是 Bean 的生命周期?

整体来讲,Bean 的生命周期大概有以下几个阶段:

  1. 实例化 Instantiation
  2. 属性赋值 Populate
  3. 初始化 Initialization
  4. 销毁 Destruction
@Configuration
public class MainConfig { 
		//指定了bean的生命周期的初始化方法和销毁方法.
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

如前诉,Spring IoC 容器分为 BeanFactory 和 ApplicationContext,这两种容器中 Bean 的生命周期大体上是相同的,在本节中主要介绍 BeanFactory 中 Bean 的生命周期。

  • 针对单实例 bean 的话,容器启动的时候,bean 的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法。
  • 针对多实例 bean 的话,容器启动的时候,bean 是不会被创建的而是在获取 bean 的时候被创建,而且 bean 的销毁不受 IOC 容器的管理。

FactoryBean 中 Bean 的生命周期
FactoryBean 中 Bean 的生命周期

Ⅰ Bean 的实例化

(1)当调用者通过 getBean(beanName) 向容器请求某一个 Bean 时,如果容器注册了InstantiationAwareBeanPostProcessor 接口,则在实例化 Bean 之前,将调用接口的 postProcessBeforeInstantiation() 方法。

(2)根据配置情况调用 Bean 构造函数或工厂方法实例化 Bean。

(3)如果容器注册了 InstantiationAwareBeanPostProcessor 接口,那么在实例化 Bean 之后,调用该接口的 postProcessAfterInstantiation() 方法,可在这里对已经实例化的对象进行一些 “梳妆打扮”。

Ⅱ Bean 属性赋值

(4) 如果 Bean 配置了属性信息,那么容器在这一步着手将配置值设置到 Bean 对应的属性中,不过在设置每个属性之前将先调用 InstantiationAwareBeanPostProcessor 接口的 postProcessPropertyValues() 方法。

(5) 调用 Bean 的属性设置方法设置属性值

(6)如果 Bean 实现了BeanNameAware 接口,则将调用 setBeanName() 接口方法,将配置文件中该Bean对应的名称设置到Bean中

(7)如果 Bean实现了BeanFactoryAware接口,则将调用 setBeanFactory() 接口方法,将 BeanFactory容器实例设置到 Bean 中

Ⅲ Bean 的初始化

(8)如果 BeanFactory 装配了 BeanPostProcessor 后置处理器,则将调用 BeanPostProcessorObject postProcessBeforeInitialization(Object bean,String beanName) 接口方法对 Bean 进行加工操作。其中,入参 bean 是当前正在处理的 Bean,而 beanName 是当前 Bean 的配置名,返回的对象为加工处理后的 Bean,用户可以使用该方法对某些Bean进行特殊的处理,甚至改变Bean 的行为。BeanPostProcessor 在 Spring 框架中占有重要的地位,为容器提供对 Bean进行后续加工处理的切入点,Spring 容器所提供的各种“神奇功能”(如AOP、动态代理等)都通过 BeanPostProcessor 实现。

(9) 如果 Bean 实现了 InitializingBean 接口,则将调用接口的 afterPropertiesSet() 方法。

(10) 如果在 <bean> 中通过 init-method 属性定义了初始化方法,则将执行这个方法。

(11) BeanPostProcessor 后置处理器定义了两个方法:其一是 postProcessBeforeInitialization(),在第(8)步调用;其二是 Object postProcessAfterInitialization(Object bean,String beanName),这个方法在此时调用,容器再次获得对 Bean 进行加工处理的机会。

(12)如果在 <bean> 中指定 Bean 的作用范围为 scope=“prototype”,则将 Bean 返回给调用者,调用者负责 Bean 后续生命的管理,Spring 不再管理这个 Bean 的生命周期。如果将作用范围设置为scope=“singleton”,则将 Bean 放入 Spring loC 容器的缓存池中,并将 Bean 引用返回给调用者,Spring继续对这些Bean进行后续的生命管理。

Ⅳ Bean 销毁

(13)对于 scope=“singleton” 的 Bean(默认情况),当容器关闭时,将触发 Spring 对 Bean 后续生命周期的管理工作。如果 Bean 实现了DisposableBean接口,则将调用接口的 destory()方法,可以在此编写释放资源、记录日志等操作。

(14) 对于 scope=“singleton” 的 Bean,如果通过 <bean> 的 destroy-method 属性指定了 Bean 的销毁方法,那么 Spring 将执行 Bean 的这个方法,完成 Bean 资源的释放等操作。

Bean的完整生命周期从 Spring 容器着手实例化 Bean开始,直到最终销毁 Bean。其中经过了许多关键点,每个关键点都涉及特定的方法调用,可以将这些方法大致划分为4类。

  1. Bean自身的方法:如调用 Bean 构造函数实例化 Bean、调用 Setter 设置 Bean 的属性值及通过<bean>的 init-method 和 destroy-method 所指定的方法。
  2. Bean级生命周期接口方法:如BeanNameAware、BeanFactoryAware、ApplicationContextAware,即仅仅对实现了该接口的指定Bean有效,所以其使用方法是在要使用该功能的Bean自己来实现该接口。
  3. 容器级生命周期接口方法:在上图中带 “★” 的步骤是由 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现的,一般称它们的实现类为“后处理器”。后处理器接口一般不由 Bean 本身实现,它们独立于 Bean,实现类以容器附加装置的形式注册到 Spring 容器中,并通过接口反射为 Spring 容器扫描识别。当 Spring 容器在处理其他Bean的某些时刻就会回调响应的接口中的方法,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣的 Bean 进行加工处理。
  4. 工厂后处理器接口方法:包括 AspectJWeavingEnabler、CustomAutowireConfigurer、ConfigurationClassPostProcessor 等方法。工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用。

Spring 扩展点接口

理解了上面的 Bean 的生命周期之后,阅读本节内容就很轻松了,本节主要是梳理了一下上面提到的各种扩展点。

我将介绍其中常用的几个扩展点以及它们的使用场景。

扩展接口作用
BeanPostProcessor支持在 Bean 初始化前、后对 Bean 进行处理
BeanFactoryPostProcessor处理所有 Bean 前,对 BeanFactory 进行预处理
BeanDefinitionRegistryPostProcessor可以添加自定义的Bean
nitializingBean在 Bean 创建完成,所有属性注入完成之后执行
DisposableBean在 Bean 销毁前执行
Aware 接口族获得 Spring 容器资源
FactoryBean复杂 Bean 注入
ApplicationListener监听响应容器事件

两种 PostProcessor

  1. 一个是针对BeanDefinition的容器级别的后处理器 - BeanFactoryPostProcessor
  2. 一个是针对getBean操作获得的对象的后处理器 - BeanPostProcessor

BeanFactory 和 ApplicationContext 都支持 BeanPostProcessor、BeanFactoryPostProcessor 的使用,但两者之间的区别是:BeanFactory 需要手动注册,而 ApplicationContext 则是自动注册。

两者的不同:

  • 触发时机不同,前者 BeanFactoryPostProcessor 是在容器 refresh 方法中调用,而后者实际调用时机是在 getBean 方法获取对象时调用;因触发时机不同导致二者处理的对象不同。BeanFactoryPostProcessor 处理的是解析完配置文件后注册在容器中的 BeanDefinition,而 BeanPostProcessor 处理的是通过反射生成的实例 Bean;

  • 接口样式不同,BeanFactoryPostProcessor 只有一个后处理方法,而 BeanPostProcessor 有一个前置处理方法一个后置处理方法。

BeanPostProcessor

BeanPostProcessor 提供对 bean 实例的操作扩展,在 spring 容器对 bean 实例化和设置依赖之后,其回调开始执行。BeanPostProcessor 接口定义的两个方法,分别在 bean 的初始化方法(InitializingBean 接口,或者 init-method 定义)执行的前后执行:

BeanPostProcessor 扩展点
BeanPostProcessor 扩展点

如果你想在 Spring 容器完成实例化,配置和初始化bean之后实现一些自定义逻辑,则可以插入一个或多个自定义BeanPostProcessor 实现。这些实现成为后置处理器。

BeanPostProcessor 接口包含两个回调方法。当实现此接口类通过容器注册为后处理器时,由 Spring 容器实例的 Bean, Spring 容器会在 bean 的 init 方法执行前回调 postProcessBeforeInitialization 方法,然后会在 bean 初始化之后回调postProcessAfterInitialization 方法。

后置处理器可以对这些 Bean 做任何自定义操作。一些 Spring Aop 的基础实现类就是通过实现 BeanPostProcessor 从而提供代理包装逻辑 。Spring 容器能够自动检测任何实现了 BeanPostProcessor 接口的 Bean。容器会自动将这些bean注册成后置处理器以便后续调用。另外我们可以定义多个 BeanPostProcessor,他们执行的顺序可以通过实现PriorityOrdered、Ordered 接口来控制。

BeanPostProcessor 的使用代码类似于如下形式:

/**
 * 自定义HelloWorldBeanPostProcessor实现BeanPostProcessor接口
 */
@Component
public class HelloWorldBeanPostProcessor implements BeanPostProcessor {
 
    @Autowired
    private ApplicationContext applicationContext;
 
    // 直接返回实例化的bean,在bean初始化之前执行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization: " + bean + ", " +  beanName + ", " + applicationContext.getApplicationName());
        return bean;
    }
 
    // 直接返回实例化的bean,在bean初始化之后执行
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization: " + bean + ", " +  beanName + ", " + applicationContext.getApplicationName());
        return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("BeanPostProcessor织入,Spring AOP实现原理");
                return method.invoke(bean, args);
            }
        });
    }
}

BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的工厂进行处理。这是Spring容器的另外一个扩展点,和BeanPostProcessor不同的地方在于,它是对beanDefiniton进行操作。实现该接口,可以在spring的bean创建之前,修改bean的定义属性。

当调用 BeanFactoryPostProcess 方法时,这时候bean还没有实例化,此时 Bean 刚被解析成 BeanDefinition对象。也就是说,Spring 允许 BeanFactoryPostProcessor 在容器实例化任何其它 bean 之前读取配置元数据,并可以根据需要进行修改,例如可以把 bean 的 scope 从 singleton 改为 prototype,也可以把 property 的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置 ‘order’ 属性或实现 ordered 接口来控制各个 BeanFactoryPostProcessor 的执行次序, 这些和BeanPostProcessor很类似,并且其启用方式和容器相关性也与之一致。

注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息,例如

BeanDefinition obj = arg0.getBeanDefinition("sumBean");

Spring 内置实现了很多的 BeanFactoryPostProcessor 实现,例如:

org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
org.springframework.beans.factory.config.PropertyOverrideConfigurer
org.springframework.beans.factory.config.CustomEditorConfigurer:用来注册自定义的属性编辑器。

下面的代码演示了实现 BeanFactoryPostProcessor#postProcessBeanFactory 接口,用于修改 BeanDefinition 的功能:

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println(" IOC 容器调用了 YjBeanFactoryPostProcessor 的 postProcessBeanFactory方法");
        for(String name:beanFactory.getBeanDefinitionNames()) {
            if("yjLog".equals(name)) {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
                //beanDefinition.setLazyInit(true);
            }
        }
    }
}

下面的示例代码演示了 实现 BeanFactoryPostProcessor#postProcessBeanFactory 接口,用于在 Bean 初始化之前,修改 Bean 属性值的操作:

@Component
public class HelloWorldBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    // 实现BeanFactoryPostProcessor,在spring的bean创建之前,对beanDefinition进行操作,修改bean的定义属性
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 1);
        beanDefinitionBuilder.addPropertyValue("name", "jak");
        defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
 
    }
}

程序入口,获取User并输出。

public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        // 并没有对 user 进行初始化
        User user = (User) applicationContext.getBean("user");
        System.out.println(user.toString());
    }
}

// AppConfig
@Configuration
@ComponentScan(value = "com.test")
public class AppConfig {
}

// User
@Component
public class User {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public User setId(Integer id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return name;
    }

    public User setName(String name) {
        this.name = name;
        return this;
    }
}

程序输出结果,如下:

BeanDefinitionRegistryPostProcessor

这个接口继承了 BeanFactoryPostProcessor。 从名字上来看, 这个接口是 BeanDefinitionRegistry 的后处理器,

我们先介绍下BeanDefinitionRegistry。BeanDefinitionRegistry是用来注册BeanDefinition的。 BeanDefinition 就是 Bean 的配置元数据或Bean的描述信息, 比如Bean的属性值, 构造方法的参数值等. 上面的 BeanFactory 的 BeanDefinition 也是由它注册的。

BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的扩展, 允许在 BeanFactoryPostProcessor 被调用之前对 BeanDefinition 做一些操作, 尤其是它可以注册 BeanFactoryPostProcessor 的BeanDefinition。它提供了一个方法postProcessBeanDefinitionRegistry(), 这个方法被调用的时候, 所有的BeanDefinition已经被加载了, 但是所有的Bean还没被创建。

注意:

  • 所有的Bean生成都有个顺序: 定义 –> 创建 –> 初始化
  • BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法在Bean被定义但还没被创建的时候执行
  • BeanFactoryPostProcessor的postProcessBeanFactory方法在Bean被创建但还没被初始化的时候执行
@Component
public class BestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
 
    //该方法用来注册更多的bean到spring容器中
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法");
        //框架自己的  BeanDefiniton  Count
        System.out.println("bean定义的数据量:" + registry.getBeanDefinitionCount());
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BestBeanDefinitionRegistryPostProcessor.class);
        registry.registerBeanDefinition("bestBeanDefinitionRegistryPostProcessor", rootBeanDefinition);
    }
 
    // 继承自BeanFactoryPostProcessor的方法 主要用来对bean定义做一些改变
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法");
        System.out.println("bean定义的数据量:" + beanFactory.getBeanDefinitionCount());
    }
}
public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        BestBeanDefinitionRegistryPostProcessor bestBeanDefinitionRegistryPostProcessor = (BestBeanDefinitionRegistryPostProcessor) applicationContext.getBean("bestBeanDefinitionRegistryPostProcessor");
        System.out.println(bestBeanDefinitionRegistryPostProcessor.getClass().getCanonicalName());
    }
}

执行结果:

InitializingBean和DisposableBean

Spring 中定义了 3 种自定义初始化和销毁方法。

  1. 通过 @Bean 指定 init-method 和 destroy-method 属性
  2. Bean实现 InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
  3. @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法

初始化和销毁
初始化和销毁

Spring bean 通过实现 InitializingBean ,DisposableBean 接口实现初始化方法和销毁前操作

这个接口有一个方法:afterPropertiesSet, 该方法在所有的属性都被赋值后调用. 属性被赋值是在初始化的时候做的, 与BeanPostProcessor结合来看,

afterPropertiesSet方法将在postProcessBeforeInitialization和postProcessAfterInitialization之间被调用。

@Component
public class Student implements InitializingBean, DisposableBean {
 
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }
 
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet");
    }
}
@Configuration
@ComponentScan(value = "com.test")
public class AppConfig {
 
}
public class Main {
    public static void main(String[] args) {

        /**
         * 1.把类扫描出来--扫描以后干了什么事情
         * 2.把bean实例化
         */
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Student student = applicationContext.getBean(Student.class);
        System.out.println(student.getClass().getName());
        applicationContext.close();
    }
}

运行结果:

Aware接口

Spring 中提供了各种 Aware 接口,如果检测到一个 bean 实现了 Aware 接口,则能在 bean 中获取相应的 Spring 资源;

如果某个对象实现了某个 Aware 接口,比如需要依赖 Spring 的上下文容器(ApplicationContext),则可以实现 ApplicationContextAware 接口。

Spring 在 Bean 进行初始化(注意与实例化的区别)之前,会将依赖的 ApplicationContext 对象通过调用 ApplicationContextAware#setApplicationContext 注入。

Spring 提供的Aware接口如下

Aware接口set属性属性含义
BeanNameAwaresetBeanNameBean在BeanFactory中的名称
BeanClassLoaderAwaresetBeanClassLoaderBean的ClassLoader
BeanFactoryAwaresetBeanFactoryBean所在的BeanFactory
EnvironmentAwaresetEnvironmentBean运行时依赖的Environment
EmbeddedValueResolverAwaresetEmbeddedValueResolverSpring EL解析
ResourceLoaderAwaresetApplicationEventPublisher加载Bean的ResourceLoader
ApplicationEventPublisherAwaresetApplicationEventPublisher应用事件发布者
MessageSourceAwaresetMessageSource国际化
ApplicationContextAwaresetApplicationConext应用上下文
ServletContextAwaresetServletContextServlet上下文

那么这些Aware接口在源码中是什么时候调用的呢?查看 AbstractAutowireCapableBeanFactory#invokeAwareMethods 源码:

AbstractAutowireCapableBeanFactory#invokeAwareMethods
AbstractAutowireCapableBeanFactory#invokeAwareMethods

调用顺序:

AbstractAutowireCapableBeanFactory 中 Aware 的调用顺序
AbstractAutowireCapableBeanFactory 中 Aware 的调用顺序

其他的Aware接口呢?通过 ApplicationContextAwareProcessor,如需,请自行查看源码。

ApplicationContextAwareProcessor 处理 Aware 扩展点顺序
ApplicationContextAwareProcessor 处理 Aware 扩展点顺序

@Component
public class BestApplicationContextAware implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        String[] beanDefinitionNames = this.applicationContext.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));
    }
}
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        BestApplicationContextAware bestApplicationContextAware = (BestApplicationContextAware) applicationContext.getBean("bestApplicationContextAware");
        System.out.println(bestApplicationContextAware.getClass().getCanonicalName());
    }
}

FactoryBean

一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean 。

在某些情况下,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 bean 中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

Spring 为此提供了一个org.Springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。

后面 Spring 又提供了@Configration 和 @Bean 这种方式,一定程度上可以替代 FactoryBean

FactoryBean 接口的定义如下:

public interface FactoryBean<T> {
 
	@Nullable
	T getObject() throws Exception;
 
	@Nullable
	Class<?> getObjectType();
 
	default boolean isSingleton() {
		return true;
	}
}

它定义了三个方法:

  • Object getObject():返回此工厂创建的对象实例。可以共享实例,这取决于该工厂返回的是单例还是原型。
  • Class getObjectType():返回 getObject 方法返回的对象类型,如果类型事先不知道,则返回 null。
  • boolean isSingleton():如果 FactoryBean 返回单例,则返回 ture,否则返回 false

当你想在容器中获得对应 bean 的 FactoryBean 实例的时候,需要在 BeanName 前面加上 ‘&'。例如: getBean("myBean") 返回的是一个叫做 myBean 的 Bean,但是 getBean("&myBean") 返回的是对应的 FactoryBean。

应用场景:FactoryBean 通常用来创建比较复杂的 Bean。一般的 Bean 可以直接用 xml 配置,但如果一个 bean 的创建过程涉及到很多其他的 bean 和复杂的逻辑,用 xml 配置比较困难,这时候可以考虑使用 FactoryBean。例如:

@Component
public class BestFactoryBean implements FactoryBean<User> {
 
    private String userInfo;
 
    public User getObject() throws Exception {
        User User = new User();
        String[] infos = userInfo.split(",");
        User.setId(Integer.parseInt(infos[0]));
        User.setName(infos[1]);
        return User;
    }
 
    public Class<User> getObjectType() {
        return User.class;
    }
 
    public boolean isSingleton() {
        return false;
    }
 
    public String getUserInfo() {
        return this.userInfo;
    }
 
    // 接受逗号分割符设置属性信息
    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }
}

ApplicationListener

这跟 Servlet 中的监听器一样,采用了观察者模式。监听器往往都是监听某些事件源,

下面是配合 ApplicationContextAware 一起使用的例子。

  1. 定义事件
  2. 自定义 Bean,获得 ApplicationContext
  3. 自定义监听器,监听事件
  4. 利用自定义 Bean 中的 ApplicationContext 发布事件:applicationContext.publishEvent(new RumenEvent())

例如:

// 自定义事件
public class RumenEvent extends ApplicationEvent {
    public RumenEvent(Object source) {
        super(source);
    }
}
// 自定义 Bean 实现 ApplicationContextAware 接口
@Component
public class RumenzBean implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private String name;
    public void setApplicationContext(ApplicationContext context) {
        this.applicationContext = context;
    }
    // 当调用 setName 时, 触发事件
    public void setName(String name) {
        this.name = name;
        applicationContext.publishEvent(new RumenEvent(this));  // 这行代码执行完会立即被监听到
    }
    public String getName() {
        return name;
    }
}
// 自定义监听器, 监听上面的事件
@Component
public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof RumenEvent) {
            System.out.println(((RumenzBean)event.getSource()).getName());
        }
    }
}

参考