BeanFactoryAware源码分析

BeanFactoryAware

一、基本信息

✒️ 作者 - Lex 📝 博客 - 我的CSDN 📚 文章目录 - 所有文章 🔗 源码地址 - 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;

}

四、主要功能

  1. 获取 BeanFactory 引用

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

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

    • 获取 BeanFactory 的引用不仅仅是为了查找其他 beans,bean 还可以与其所在的 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
验证账号密码成功

六、时序图

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

七、源码分析

首先来看看启动类入口,上下文环境使用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;
    }
}

八、注意事项

  1. 生命周期时机

    • setBeanFactory 方法是在 bean 属性设置之后但在其他初始化方法(如 @PostConstructInitializingBean#afterPropertiesSet 或指定的初始化方法)之前调用的。
  2. 避免循环依赖

    • 当 beans 通过 BeanFactory 查找其他 beans 时,可能会出现循环依赖的情况。例如,bean A 在其 setBeanFactory 方法中查找 bean B,而 bean B 在其 setBeanFactory 方法中查找 bean A。这种情况会导致容器初始化失败。
  3. 知道 bean 的作用域

    • 当从 BeanFactory 获取 beans 时,请记住 bean 的作用域。如果 bean 是原型作用域的,每次 getBean 调用都会返回一个新的实例。
  4. 不要过度自定义

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

九、总结

最佳实践总结
  1. 构建与配置

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

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

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

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

    • 当调用 validateUser 方法验证用户名和密码时,根据所选择的验证器(在此示例中是 SimpleUserValidator),将输出相应的验证信息。此外,验证器本身也输出了它正在使用的验证方法。
源码分析总结
  1. 应用启动与上下文初始化

    • 当启动类 BeanNameAwareApplication 被执行,一个新的 AnnotationConfigApplicationContext 被创建并初始化,其中传入了配置类 MyConfiguration
  2. 配置类与组件扫描

    • MyConfiguration 是一个 Java 配置类,它告诉 Spring 容器去扫描特定的包以查找组件。
  3. 单例bean的预实例化

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

    • 在上下文刷新的过程中,Spring 容器会逐个创建并初始化所有的单例bean。doCreateBean 方法负责实例化bean、注入依赖、并调用任何初始化方法。
  5. 处理 Aware 接口

    • 对于实现了 Aware 接口的bean,如 BeanFactoryAware,在初始化过程中,Spring 容器会调用相应的 Aware 方法(例如,setBeanFactory)。这使得bean可以获得关于其运行环境的信息或其他 Spring 功能。
  6. 自定义逻辑执行

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

    • 通过实现 BeanFactoryAwareUserService 能够获得对 BeanFactory 的访问权限。这使得它可以在运行时动态地从 BeanFactory 中获取bean,如在示例中的 UserValidator
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`GatewayProxyFactoryBean` 是 Spring Cloud Gateway 的核心组件之一,它的作用是根据用户定义的配置信息创建一个网关代理对象。下面对其码进行分析。 1. 继承关系 `GatewayProxyFactoryBean` 继承自 `AbstractGatewayProxyFactoryBean` 类,该类实现了 `FactoryBean` 接口和 `BeanFactoryAware` 接口: ```java public abstract class AbstractGatewayProxyFactoryBean<T extends WebFluxGatewaySupport> implements FactoryBean<T>, BeanFactoryAware { // ... @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } // ... } ``` 2. 配置属性 `GatewayProxyFactoryBean` 类中定义了多个配置属性,这些属性用于配置网关代理对象的行为。例如,`routes` 属性用于配置路由规则,`filters` 属性用于配置过滤器规则,`properties` 属性用于配置额外的属性等。 ```java public class GatewayProxyFactoryBean extends AbstractGatewayProxyFactoryBean<WebFluxGatewaySupport> { private List<RouteDefinition> routes = new ArrayList<>(); private List<GatewayFilterDefinition> filters = new ArrayList<>(); private Map<String, Object> properties = new HashMap<>(); // ... public void setRoutes(List<RouteDefinition> routes) { this.routes = routes; } public void setFilters(List<GatewayFilterDefinition> filters) { this.filters = filters; } public void setProperties(Map<String, Object> properties) { this.properties = properties; } // ... } ``` 3. getObject() 方法 `GatewayProxyFactoryBean` 中最重要的方法就是 `getObject()` 方法,它用于创建一个网关代理对象。具体实现如下: ```java @Override public WebFluxGatewaySupport getObject() throws Exception { // 创建一个 WebFluxGatewaySupport 对象 WebFluxGatewaySupport gateway = new WebFluxGatewaySupport(); // 设置路由规则 if (!CollectionUtils.isEmpty(this.routes)) { gateway.setRoutes(this.routes); } // 设置过滤器规则 if (!CollectionUtils.isEmpty(this.filters)) { gateway.setFilters(this.filters); } // 设置额外的属性 if (!CollectionUtils.isEmpty(this.properties)) { gateway.setProperties(this.properties); } // 初始化 gateway.afterPropertiesSet(); return gateway; } ``` 在 `getObject()` 方法中,首先创建了一个 `WebFluxGatewaySupport` 对象,并根据用户的配置信息设置了路由规则、过滤器规则和额外的属性。最后调用 `afterPropertiesSet()` 方法进行初始化并返回创建的网关代理对象。 4. 总结 `GatewayProxyFactoryBean` 是 Spring Cloud Gateway 的核心组件之一,它通过用户配置信息创建一个网关代理对象。在它的实现中,通过继承 `AbstractGatewayProxyFactoryBean` 类,实现了 `FactoryBean` 接口和 `BeanFactoryAware` 接口,并定义了多个配置属性。最重要的方法是 `getObject()` 方法,它用于创建一个网关代理对象,并根据用户的配置信息进行初始化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值