spring-reading./spring-aware-beanFactoryAware/README.md

24 KiB
Raw Blame History

BeanFactoryAware

一、接口描述

BeanFactoryAware 接口,允许 Spring bean 获得其所在的 BeanFactory 的引用。当一个 bean 实现了这个接口Spring 容器在初始化该 bean 时,会自动调用 setBeanFactory() 方法,并传递一个 BeanFactory 实例。

二、接口源码

BeanFactoryAware 是 Spring 框架自 11.03.2003 开始引入的一个核心接口。允许 Spring beans 获知并与其所在的 BeanFactory 进行交互。这为 beans 提供了直接访问 BeanFactory 的能力,进而可以查询和交互其他的 beans。

/**
 * 由希望知道其所属的 BeanFactory 的 beans 实现的接口。
 *
 * 例如beans 可以通过工厂查找合作的 beans依赖查找 * 请注意,大多数 beans 会选择通过相应的 bean 属性或构造函数参数
 * 接收对合作 beans 的引用(依赖注入)。
 *
 * 有关所有 bean 生命周期方法的列表,请参阅
 * BeanFactory BeanFactory javadocs。
 *
 * @author Rod Johnson
 * @author Chris Beams
 * @since 11.03.2003
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see InitializingBean
 * @see org.springframework.context.ApplicationContextAware
 */
public interface BeanFactoryAware extends Aware {

	/**
	 * 向 bean 实例提供其拥有的工厂的回调。
	 * 在正常 bean 属性填充之后但在初始化回调之前(如
	 * InitializingBean#afterPropertiesSet() 或自定义的初始化方法)调用。
	 * @param beanFactory 拥有的 BeanFactory永远不会是 null	 * bean 可以立即调用工厂上的方法。
	 * @throws BeansException 初始化错误的情况下
	 * @see BeanInitializationException
	 */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

三、主要功能

获取 BeanFactory 引用 通过实现 BeanFactoryAware 接口并重写 setBeanFactory 方法bean 在初始化过程中会收到其所属的 BeanFactory 的引用。Spring 容器会自动为实现了该接口的 bean 调用 setBeanFactory 方法。

依赖查找 一旦 bean 有了 BeanFactory 的引用,它就可以使用这个工厂来动态地查找其他 beans。这种方式被称为“依赖查找”Dependency Lookup与常见的“依赖注入”Dependency Injection方式相对。

BeanFactory 进行交互 获取 BeanFactory 的引用不仅仅是为了查找其他 beansbean 还可以与其所在的 BeanFactory 进行更广泛的互动,例如检查 bean 的作用域、检查 bean 是否为单例、或获取 bean 的别名等。

四、最佳实践

首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个MyConfiguration组件类。然后从Spring上下文中获取一个UserService类型的bean最后调用validateUser方法。

public class BeanNameAwareApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        UserService userService = context.getBean(UserService.class);
        userService.validateUser("root", "123456");
    }
}

使用@ComponentScan注解,告诉 Spring 容器去 "com.xcs.spring.validate" "com.xcs.spring.service"扫描包及其子包

@Configuration
@ComponentScan({"com.xcs.spring.validate", "com.xcs.spring.service"})
public class MyConfiguration {

}

UserValidator是一个简单的验证器接口,具有一个方法 validate用于验证用户名和密码是否有效。SimpleUserValidator是一个实现。它进行简单的验证仅检查用户名和密码是否为非空。ComplexUserValidatorUserValidator 接口的另一个实现。这个验证器有点复杂,除了检查用户名和密码是否为空外,还检查用户名的长度是否大于 5 以及密码的长度是否大于 8。

public interface UserValidator {
    boolean validate(String username, String password);
}

@Component("simpleUserValidator")
public class SimpleUserValidator implements UserValidator {
    @Override
    public boolean validate(String username, String password) {
        System.out.println("使用SimpleUserValidator");
        return username != null && password != null;
    }
}

@Component("complexUserValidator")
public class ComplexUserValidator implements UserValidator {
    @Override
    public boolean validate(String username, String password) {
        System.out.println("使用ComplexUserValidator");
        return username != null && username.length() > 5 && password != null && password.length() > 8;
    }
}

UserService 类利用了 Spring 的 BeanFactoryAwareInitializingBean 接口,动态地选择了一个验证器。这种设计提供了极大的灵活性,允许 UserService 根据不同的配置或条件使用不同的验证方法。这也意味着在未来,如果需要添加更多的验证方法,只需简单地添加新的验证器实现,然后在 someConfigurationMethod() 中进行相应的调整。

@Service
public class UserService implements BeanFactoryAware, InitializingBean {

    private BeanFactory beanFactory;
    private UserValidator userValidator;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (someConfigurationMethod()) {
            userValidator = beanFactory.getBean("simpleUserValidator", UserValidator.class);
        } else {
            userValidator = beanFactory.getBean("complexUserValidator", UserValidator.class);
        }
    }

    public void validateUser(String username, String password) {
        boolean success = userValidator.validate(username, password);
        if (success){
            System.out.println("验证账号密码成功");
        }else{
            System.out.println("验证账号密码失败");
        }
    }

    private boolean someConfigurationMethod() {
        return true;
    }
}

运行结果发现,使用了SimpleUserValidator来验证账号密码,并且验证成功。

使用SimpleUserValidator
验证账号密码成功

五、时序图

sequenceDiagram
    Title: BeanFactoryAware时序图
    participant BeanFactoryAwareApplication
    participant AnnotationConfigApplicationContext
    participant AbstractApplicationContext
    participant DefaultListableBeanFactory
    participant AbstractBeanFactory
    participant DefaultSingletonBeanRegistry
    participant AbstractAutowireCapableBeanFactory
    participant UserService
    
    BeanFactoryAwareApplication->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext(componentClasses)<br>创建上下文
    AnnotationConfigApplicationContext->>AbstractApplicationContext:refresh()<br>刷新上下文
    AbstractApplicationContext->>AbstractApplicationContext:finishBeanFactoryInitialization(beanFactory)<br>初始化Bean工厂
    AbstractApplicationContext->>DefaultListableBeanFactory:preInstantiateSingletons()<br>实例化单例
    DefaultListableBeanFactory->>AbstractBeanFactory:getBean(name)<br>获取Bean
    AbstractBeanFactory->>AbstractBeanFactory:doGetBean(name,requiredType,args,typeCheckOnly)<br>执行获取Bean
    AbstractBeanFactory->>DefaultSingletonBeanRegistry:getSingleton(beanName,singletonFactory)<br>获取单例Bean
    DefaultSingletonBeanRegistry-->>AbstractBeanFactory:getObject()<br>获取Bean实例
    AbstractBeanFactory->>AbstractAutowireCapableBeanFactory:createBean(beanName,mbd,args)<br>创建Bean
    AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:doCreateBean(beanName,mbd,args)<br>执行Bean创建
    AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:initializeBean(beanName,bean,mbd)<br>负责bean的初始化
    AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:invokeAwareMethods(beanName, bean)<br>调用Aware方法
    AbstractAutowireCapableBeanFactory->>UserService:setBeanFactory(beanFactory)<br>设置beanFactory
    AbstractAutowireCapableBeanFactory-->>AbstractBeanFactory:返回Bean对象
    AbstractBeanFactory-->>DefaultListableBeanFactory:返回Bean对象
    AnnotationConfigApplicationContext-->>BeanFactoryAwareApplication:初始化完成

六、源码分析

首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个MyConfiguration组件类。然后从Spring上下文中获取一个UserService类型的bean最后调用validateUser方法。

public class BeanNameAwareApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
        UserService userService = context.getBean(UserService.class);
        userService.validateUser("root", "123456");
    }
}

org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext构造函数中,执行了三个步骤,我们重点关注refresh()方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}

org.springframework.context.support.AbstractApplicationContext#refresh方法中我们重点关注一下finishBeanFactoryInitialization(beanFactory)这方法会对实例化所有剩余非懒加载的单列Bean对象其他方法不是本次源码阅读的重点暂时忽略。

@Override
public void refresh() throws BeansException, IllegalStateException {
    // ... [代码部分省略以简化]
    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);
    // ... [代码部分省略以简化]
}

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization方法中,会继续调用DefaultListableBeanFactory类中的preInstantiateSingletons方法来完成所有剩余非懒加载的单列Bean对象。

/**
 * 完成此工厂的bean初始化实例化所有剩余的非延迟初始化单例bean。
 * 
 * @param beanFactory 要初始化的bean工厂
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // ... [代码部分省略以简化]
    // 完成所有剩余非懒加载的单列Bean对象。
    beanFactory.preInstantiateSingletons();
}

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons方法中主要的核心目的是预先实例化所有非懒加载的单例bean。在Spring的上下文初始化完成后该方法会被触发以确保所有单例bean都被正确地创建并初始化。其中getBean(beanName)是此方法的核心操作。对于容器中定义的每一个单例bean它都会调用getBean方法这将触发bean的实例化、初始化及其依赖的注入。如果bean之前没有被创建过那么这个调用会导致其被实例化和初始化。

public void preInstantiateSingletons() throws BeansException {
    // ... [代码部分省略以简化]
    // 循环遍历所有bean的名称
    for (String beanName : beanNames) {
        getBean(beanName);
    }
    // ... [代码部分省略以简化]
}

org.springframework.beans.factory.support.AbstractBeanFactory#getBean()方法中,又调用了doGetBean方法来实际执行创建Bean的过程传递给它bean的名称和一些其他默认的参数值。此处doGetBean负责大部分工作如查找bean定义、创建bean如果尚未创建、处理依赖关系等。

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法中首先检查所请求的bean是否是一个单例并且已经创建。如果尚未创建它将创建一个新的实例。在这个过程中它处理可能的异常情况如循环引用并确保返回的bean是正确的类型。这是Spring容器bean生命周期管理的核心部分。

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // ... [代码部分省略以简化]

    // 开始创建bean实例
    if (mbd.isSingleton()) {
        // 如果bean是单例的我们会尝试从单例缓存中获取它
        // 如果不存在则使用lambda创建一个新的实例
        sharedInstance = getSingleton(beanName, () -> {
            try {
                // 尝试创建bean实例
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // ... [代码部分省略以简化]
            }
        });
        // 对于某些bean例如FactoryBeans可能需要进一步处理以获取真正的bean实例
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // ... [代码部分省略以简化]

    // 确保返回的bean实例与请求的类型匹配
    return adaptBeanInstance(name, beanInstance, requiredType);
}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton()方法中主要负责从单例缓存中获取一个已存在的bean实例或者使用提供的ObjectFactory创建一个新的实例。这是确保bean在Spring容器中作为单例存在的关键部分。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // 断言bean名称不能为空
    Assert.notNull(beanName, "Bean name must not be null");

    // 同步访问单例对象缓存,确保线程安全
    synchronized (this.singletonObjects) {
        // 从缓存中获取单例对象
        Object singletonObject = this.singletonObjects.get(beanName);

        // 如果缓存中没有找到
        if (singletonObject == null) {
            // ... [代码部分省略以简化]

            try {
                // 使用工厂创建新的单例实例
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // ... [代码部分省略以简化]
            }
            catch (BeanCreationException ex) {
                // ... [代码部分省略以简化]
            }
            finally {
                // ... [代码部分省略以简化]
            }

            // ... [代码部分省略以简化]
        }

        // 返回单例对象
        return singletonObject;
    }
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()方法中,主要的逻辑是调用 doCreateBean,这是真正进行 bean 实例化、属性填充和初始化的地方。这个方法会返回新创建的 bean 实例。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    
    // ... [代码部分省略以简化]
    
    try {
        // 正常的bean实例化、属性注入和初始化。
        // 这里是真正进行bean创建的部分。
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        // 记录bean成功创建的日志
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // ... [代码部分省略以简化]
    }
    catch (Throwable ex) {
        // ... [代码部分省略以简化]
    }
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法中,initializeBean方法是bean初始化确保bean是完全配置和准备好的。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    // 声明一个对象后续可能用于存放初始化后的bean或它的代理对象
    Object exposedObject = bean;

    // ... [代码部分省略以简化]
    
    try {
        // ... [代码部分省略以简化]
        
        // bean初始化
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } 
    catch (Throwable ex) {
        // ... [代码部分省略以简化]
    }

    // 返回创建和初始化后的bean
    return exposedObject;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean方法中,invokeAwareMethods(beanName, bean)是一个非常重要的步骤。这个方法是为了处理实现了Spring的Aware接口族的Beans例如BeanNameAware, BeanFactoryAware。如果提供的bean实现了任何这些接口该方法会回调相应的Aware方法。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

    // ... [代码部分省略以简化]
    
    invokeAwareMethods(beanName, bean);
    
    // ... [代码部分省略以简化]

    return wrappedBean;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods方法中,用于处理实现了 Spring Aware 接口族的 beans。当一个 bean 实现了如 BeanNameAwareBeanClassLoaderAwareBeanFactoryAware 等接口时,此方法确保正确的回调方法被调用,从而为 bean 提供关于其运行环境或其他相关信息。

private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            // ... [代码部分省略以简化]
        }
        if (bean instanceof BeanClassLoaderAware) {
            // ... [代码部分省略以简化]
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

最后执行到我们自定义的逻辑中,容器将调用 setBeanFactory() 方法,并将当前的 bean factory 实例作为参数传递。

@Service
public class UserService implements BeanFactoryAware, InitializingBean {

    private BeanFactory beanFactory;
    private UserValidator userValidator;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // ... [代码部分省略以简化]
    }

    public void validateUser(String username, String password) {
        // ... [代码部分省略以简化]
    }

    private boolean someConfigurationMethod() {
        return true;
    }
}

七、注意事项

生命周期时机setBeanFactory 方法是在 bean 属性设置之后但在其他初始化方法(如 @PostConstructInitializingBean#afterPropertiesSet 或指定的初始化方法)之前调用的。

避免循环依赖:当 beans 通过 BeanFactory 查找其他 beans 时可能会出现循环依赖的情况。例如bean A 在其 setBeanFactory 方法中查找 bean B而 bean B 在其 setBeanFactory 方法中查找 bean A。这种情况会导致容器初始化失败。

知道 bean 的作用域:当从 BeanFactory 获取 beans 时,请记住 bean 的作用域。如果 bean 是原型作用域的,每次 getBean 调用都会返回一个新的实例。

不要过度自定义:除非有很好的理由,否则应避免在 setBeanFactory 方法中执行大量的自定义逻辑。这会使 bean 的初始化过程变得复杂,并可能导致不可预见的副作用。

八、总结

8.1、最佳实践总结

构建与配置:在 BeanNameAwareApplication 启动类中,使用了 AnnotationConfigApplicationContext 来基于 Java 配置类 (MyConfiguration) 初始化 Spring 上下文。这是一个 Java-based 的配置方法,与传统的 XML-based 配置相比,更加直观和灵活。

组件扫描MyConfiguration 配置类使用 @ComponentScan 注解指定了需要被扫描的包路径。Spring 容器会自动扫描这些包以及其子包下的组件,并将它们注册为 Spring beans。

验证器设计:我们设计了一个 UserValidator 接口,以及两个实现该接口的类:SimpleUserValidatorComplexUserValidator。这两个验证器具有不同的验证逻辑,以满足不同的验证需求。

动态选择验证器UserService 类是此应用的核心,它根据某些配置动态地从 BeanFactory 中选择一个验证器。这是通过实现 BeanFactoryAwareInitializingBean 接口来完成的:BeanFactoryAware 允许 UserService 访问 Spring 容器的 BeanFactory。InitializingBean` 确保在所有属性(例如依赖注入)设置完毕后,选择合适的验证器。

运行与输出:当调用 validateUser 方法验证用户名和密码时,根据所选择的验证器(在此示例中是 SimpleUserValidator),将输出相应的验证信息。此外,验证器本身也输出了它正在使用的验证方法。

8.2、源码分析总结

应用启动与上下文初始化: 当启动类 BeanNameAwareApplication 被执行,一个新的 AnnotationConfigApplicationContext 被创建并初始化,其中传入了配置类 MyConfiguration

配置类与组件扫描: MyConfiguration 是一个 Java 配置类,它告诉 Spring 容器去扫描特定的包以查找组件。

单例bean的预实例化: 在上下文的 refresh() 方法中Spring 会预先实例化所有非懒加载的单例bean。这意味着在容器启动时这些bean会被初始化。

Bean的实例化和初始化: 在上下文刷新的过程中Spring 容器会逐个创建并初始化所有的单例bean。doCreateBean 方法负责实例化bean、注入依赖、并调用任何初始化方法。

处理 Aware 接口: 对于实现了 Aware 接口的beanBeanFactoryAware在初始化过程中Spring 容器会调用相应的 Aware 方法(例如,setBeanFactory。这使得bean可以获得关于其运行环境的信息或其他 Spring 功能。

自定义逻辑执行: 一旦bean被初始化并且所有的 Aware 方法都被调用,就可以执行自定义逻辑。在这个例子中,这是通过 UserServicevalidateUser 方法来完成的。

BeanFactoryAware 的特性: 通过实现 BeanFactoryAwareUserService 能够获得对 BeanFactory 的访问权限。这使得它可以在运行时动态地从 BeanFactory 中获取bean如在示例中的 UserValidator