Spring源码分析(BeanFactory)

文章目录

Spring源码分析(BeanFactory)

一、BeanFactory

BeanFactory最顶层 的容器接口,只提供了获取Bean相关的一些方法。

java 复制代码
public interface BeanFactory {
    // 对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象
    String FACTORY_BEAN_PREFIX = "&";

    // 根据bean的名字,在IOC容器中得到bean实例,
    Object getBean(String name) throws BeansException;

    // 根据bean的名字,在IOC容器中得到bean实例,args:显式参数(必须为非单例模式)
    Object getBean(String name, Object... args) throws BeansException;

    // 根据bean的名字获得对象,并转换为Class类型(可以不用进行类型转换)
    <T> T getBean(String name, Class<T> requiredType);

    // 根据bean的类型获得对象(必须是拥有唯一实现类)
    <T> T getBean(Class<T> requiredType) throws BeansException;

    // 根据bean的类型获得对象,args:显式参数
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    // 判断IOC容器是否有这个名字的bean
    boolean containsBean(String name);

    // 判断这个bean是不是单例 
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    // 判断这个bean是不是多例 
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    // 获取bean实例的Class类型  
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    // 这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  
    String[] getAliases(String name);
}

二、ApplicationContext 的父系

ApplicationContext是更高级的容器接口,继承了许多其他接口,提供了更多的功能。

  • 获取 Environment(EnvironmentCapable)
  • getBean 的扩展(ListableBeanFactory)
  • 事件的发布与监听机制(ApplicationEventPublisher)
  • 支持父子容器(HierarchicalBeanFactory)
  • 国际化(MessageSource)
  • 事件的发布与监听机制(ApplicationEventPublisher)
  • 资源访问(ResourcePatternResolver)
java 复制代码
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    @Nullable
    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    @Nullable
    ApplicationContext getParent();

    // 用于进行手动的 Bean 注入和依赖注入
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

1、HierarchicalBeanFactory

HierarchicalBeanFactory 用于表示具有层次结构的 BeanFactory 容器。

  • 支持父子容器的关系,一个 BeanFactory 可以有一个或多个父容器。

    子容器可以访问父容器中定义的 Bean,但父容器不能访问子容器中定义的 Bean。

  • 如果子容器中不存在某个 Bean,则会委托父容器进行查找。

java 复制代码
public interface HierarchicalBeanFactory extends BeanFactory {
    @Nullable
    BeanFactory getParentBeanFactory();

    boolean containsLocalBean(String name);
}

2、ListableBeanFactory

ListableBeanFactory 扩展了 BeanFactory 接口,提供了额外的功能来 获取 Bean 及其相关信息

java 复制代码
public interface ListableBeanFactory extends BeanFactory {
    // 获取 Bean 的定义信息
    boolean containsBeanDefinition(String beanName);
    int getBeanDefinitionCount();
    String[] getBeanDefinitionNames();
    
    // 通过 类型 获取 Bean
    String[] getBeanNamesForType(ResolvableType type);
    String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
    String[] getBeanNamesForType(@Nullable Class<?> type);
    String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
    
    // 通过 注解 获取Bean
    String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);

    // 获取 <beanName, type>
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;

    // 获取 <beanName, annotation>
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;

    // 获取bean的注解
    @Nullable
    <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
        throws NoSuchBeanDefinitionException;
}

3、EnvironmentCapable

EnvironmentCapable 接口用于获取 Environment 实例

java 复制代码
public interface EnvironmentCapable {
    Environment getEnvironment();
}

Environment 用于表示运行时环境(例如配置文件、系统属性、环境变量等)的抽象,提供了访问应用程序配置信息的统一接口。

java 复制代码
public interface Environment extends PropertyResolver {
    // 返回激活profile名称的数组
	String[] getActiveProfiles();
    
	// 返回默认profile名称的数组
	String[] getDefaultProfiles();
    
    // environment是否支持给定profile
    boolean acceptsProfiles(Profiles profiles);

	@Deprecated // 弃用
	boolean acceptsProfiles(String... profiles);
}
java 复制代码
public interface PropertyResolver {
	// 检查某个属性是否存在
	boolean containsProperty(String key);

    // 获取指定属性的值(不存在则返回null)
	String getProperty(String key);
    
    // 获取指定属性的值(不存在则返回默认值)
	String getProperty(String key, String defaultValue);

    // 获取指定属性的值,可以指定要返回对象的类型(不存在则返回null)
	<T> T getProperty(String key, Class<T> targetType);
    
    // 获取指定属性的值,可以指定要返回对象的类型(不存在则返回默认值)
	<T> T getProperty(String key, Class<T> targetType, T defaultValue);

    // 获取指定属性的值(不存在则抛出异常)
	String getRequiredProperty(String key) throws IllegalStateException;
	<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;

	String resolvePlaceholders(String text);

	String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}

4、ApplicationEventPublisher

ApplicationEventPublisher 用于发布应用程序事件并通知所有已注册的事件监听器

java 复制代码
@FunctionalInterface
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }
    
    void publishEvent(Object event);
}

5、MessageSource

MessageSource 是 Spring Framework 中用于国际化支持的接口之一。

  • 它提供了一种统一的方式来访问应用程序中的消息资源,支持多语言和多地区的国际化功能。
java 复制代码
public interface MessageSource {
    String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
    String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

6、ResourcePatternResolver

ResourcePatternResolver 加载和访问应用程序中的资源,支持通配符和模式匹配,可以方便地加载多个资源。

java 复制代码
public interface ResourcePatternResolver extends ResourceLoader {
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    Resource[] getResources(String var1) throws IOException;
}
java 复制代码
public interface ResourceLoader {
    String CLASSPATH_URL_PREFIX = "classpath:";

    Resource getResource(String var1);

    @Nullable
    ClassLoader getClassLoader();
}

三、ApplicationContext 的实现

ApplicationContext 负责创建和管理应用程序中的所有 Bean 对象,其实现类的区别仅仅在于如何加载配置

  • AnnotationConfigApplicationContext:使用「注解方式」加载配置
  • ClassPathXmlApplicationContext:从「资源根目录」下加载配置
  • FileSystemXmlApplicationContext:从「文件路径下」加载配置

四、BeanFactory的创建

1、Spring中的创建

java 复制代码
// org.springframework.context.support.AbstractApplicationContext

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // ...
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // ...
    }
}
java 复制代码
// org.springframework.context.support.AbstractApplicationContext

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 刷新 BeanFactory(关闭旧的,创建新的)
    refreshBeanFactory();
    // 返回 BeanFactory
    return getBeanFactory();
}
java 复制代码
// org.springframework.context.support.AbstractRefreshableApplicationContext

@Override
protected final void refreshBeanFactory() throws BeansException {
    // ...
    try {
        // 创建 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // ...
    } catch (IOException ex) {
        throw new ApplicationContextException(...., ex);
    }
}

protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

可以看到,创建的 BeanFactory 是 DefaultListableBeanFactory

2、SpringBoot中的创建

java 复制代码
@SpringBootApplication
public class BasicProjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(BasicProjectApplication.class, args);
    }
}
java 复制代码
// org.springframework.boot.SpringApplication

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 构建 SpringApplication实例 并执行run方法
    return (new SpringApplication(primarySources)).run(args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}

public ConfigurableApplicationContext run(String... args) {
    // Spring容器
    ConfigurableApplicationContext context = null;

    try {
        // 构建Spring容器
        context = this.createApplicationContext();
    } 
    // ...
}

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    // AnnotationConfigServletWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    // AnnotationConfigReactiveWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    // AnnotationConfigApplicationContext
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
        }
    }

    // 构建IoC容器
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

可以看到,三种 contextClass 都是 GenericApplicationContext 的子类

在实例化之前,会先进行父类 GenericApplicationContext 的初始化

java 复制代码
// org.springframework.context.support.GenericApplicationContext

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

可以看到,创建的 BeanFactory 是 DefaultListableBeanFactory

五、DefaultListableBeanFactory

1、为什么选择 DefaultListableBeanFactory?

为什么创建的 BeanFactory 要选择 DefaultListableBeanFactory 呢?

分析一下继承图:

可以看到:

  • ConfigurableListableBeanFactory 只有一个实现类 DefaultListableBeanFactory
  • DefaultListableBeanFactory 还通过实现右边的 AbstractAutowireCapableBeanFactory 通吃了右路

因此,DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,这也是为什么会选择实例化这个类的原因。

2、运行时获取 DefaultListableBeanFactory

如何在运行时获取 DefaultListableBeanFactory 实例呢?

  1. getAutowireCapableBeanFactory 获取 AutowireCapableBeanFactory
  2. AutowireCapableBeanFactory 向下转型得到 DefaultListableBeanFactory
java 复制代码
public class GetDefaultListableBeanFactory {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        DefaultListableBeanFactory autowireCapableBeanFactory = 
            (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
    }
}
相关推荐
葫芦和十三5 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp6 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑6 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯7 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan9 小时前
多Agent之间的区别
后端
青石路11 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充11 小时前
1.面向对象设计思想
后端
IT_陈寒12 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro12 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗12 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端