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();
    }
}
相关推荐
2402_857589362 分钟前
SpringBoot框架:作业管理技术新解
java·spring boot·后端
HBryce245 分钟前
缓存-基础概念
java·缓存
一只爱打拳的程序猿20 分钟前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring
杨荧22 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
minDuck23 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
为将者,自当识天晓地。42 分钟前
c++多线程
java·开发语言
daqinzl1 小时前
java获取机器ip、mac
java·mac·ip
激流丶1 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue1 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
让学习成为一种生活方式1 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言