AbstractApplicationContext类源码解析

1. 整体认识

先贴一张整体结构图:
在这里插入图片描述

  • 在之前的文章解析了ApplicationContext和ConfigurableApplicationContext,现在再来了解这个类就清晰很多

  • ApplicationContext和ConfigurableApplicationContext源码解析

  • AbstractApplicationContext是ConfigurableApplicationContext接口的抽象实现,同事继承了默认资源解析类。其实在ConfigurableApplicationContext中有增加协议解析器的拓展函数,通过这个类集成DefaultResourceLoader类就能解释得通了,ConfigurableApplicationContext中的是拓展点,如果默认资源加载不能满足需求,在通过从写ConfigurableApplicationContext中的增加协议解析器来实现拓展。

从整体结构可以知道,这个类是整个ApplicationContext类的重点,基本的实现都集中在这个类中。这也是我们了解高级容器必经之路。继续撸源码

2. 具体源码分析

2.1 配置

一上来就搞了一下和ConfigurableApplicationContext相似的操作,各特定bean设置专有名称
将messageSource、lifecycleProcessor、applicationEventMulticaster这三个名称的bean起个大写的名字。
没想想通的是,为什么不在ConfigurableApplicationContext全部配置得了,非得分开呢?

/**
	 * Name of the MessageSource bean in the factory.
	 * If none is supplied, message resolution is delegated to the parent.
	 * @see MessageSource
	 */
	public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";

	/**
	 * Name of the LifecycleProcessor bean in the factory.
	 * If none is supplied, a DefaultLifecycleProcessor is used.
	 * @see org.springframework.context.LifecycleProcessor
	 * @see org.springframework.context.support.DefaultLifecycleProcessor
	 */
	public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";

	/**
	 * Name of the ApplicationEventMulticaster bean in the factory.
	 * If none is supplied, a default SimpleApplicationEventMulticaster is used.
	 * @see org.springframework.context.event.ApplicationEventMulticaster
	 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
	 */
	public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

接下来这两个配置,

/**
	 * Boolean flag controlled by a {@code spring.spel.ignore} system property that instructs Spring to
	 * ignore SpEL, i.e. to not initialize the SpEL infrastructure.
	 * ~~~~~~~~~~~~~~~~~~~~~~
	 * 由spring.spel.ignore系统属性控制的布尔标志,该属性指示Spring忽略SpEL,
	 * 即不初始化SpEL基础结构。默认值为“ false”
	 * ~~~~~~~~~~~~~~~~~~~~~~~
	 * <p>The default is "false".
	 */
	private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");

	/**
	 * Whether this environment lives within a native image.
	 * Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
	 * @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * 此环境是否存在于本地映像中
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~
	 */
	private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);

2.2 很重要的一个配置

static {
   
		// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
		// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
		ContextClosedEvent.class.getName();
	}

其实这里我也不是很清楚,这需要我继续撸源码,看后面的理解。后面再来解答

2.3 属性定义


	static {
   
		// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
		// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
		ContextClosedEvent.class.getName();
	}


	/** Logger used by this class. Available to subclasses. */
	// 获取日志类
	protected final Log logger = LogFactory.getLog(getClass());

	/** Unique id for this context, if any. */
	// 该容器唯一标识
	private String id = ObjectUtils.identityToString(this);

	/** Display name. */
	// 该容器显示名称,和id一样?
	private String displayName = ObjectUtils.identityToString(this);

	/** Parent context. */
	// 父容器
	@Nullable
	private ApplicationContext parent;

	/** Environment used by this context. */
	// 该容器的环境,这里的环配置类。关于环境配置,Spring有自己的一套,下面有写介绍。
	@Nullable
	private ConfigurableEnvironment environment;

	/** BeanFactoryPostProcessors to apply on refresh. */
	// 在容器启动后的后置处理,这里用的一个集合来保存,证明后置处理有很多,
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

	/** System time in milliseconds when this context started. */
	// 容器启动的时间,毫秒
	private long startupDate;

	/** Flag that indicates whether this context is currently active. */
	// 推测当前该容器是否启动的标志,也就是提供判断该容器当前事故处于启动状态
	private final AtomicBoolean active = new AtomicBoolean();

	/** Flag that indicates whether this context has been closed already. */
	// 推测当前该容器是否关闭的标志
	private final AtomicBoolean closed = new AtomicBoolean();

	/** Synchronization monitor for the "refresh" and "destroy". */
	// 同步监视器,用于“刷新”和“销毁”。
	private final Object startupShutdownMonitor = new Object();

	/** Reference to the JVM shutdown hook, if registered. */
	// 如果已将注册了,参考JVM关闭钩子,
	@Nullable
	private Thread shutdownHook;

	/** ResourcePatternResolver used by this context. */
	// 此容器使用的资源模式加载器
	private ResourcePatternResolver resourcePatternResolver;

	/** LifecycleProcessor for managing the lifecycle of beans within this context. */
	// 管理该容器中bean的生命周期
	@Nullable
	private LifecycleProcessor lifecycleProcessor;

	/** MessageSource we delegate our implementation of this interface to. */
	// 消息的实现类
	@Nullable
	private MessageSource messageSource;

	/** Helper class used in event publishing. */
	// 事件发布的帮助类
	@Nullable
	private ApplicationEventMulticaster applicationEventMulticaster;

	/** Application startup metrics. **/
	// 应用程序启动指标,这里就是应用程序的启动点
	private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;

	/** Statically specified listeners. */
	// 静态指定的侦听器。
	private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

	/** Local listeners registered before refresh. */
	// 刷新之前已注册本地侦听器,关于监听器的作用,有待探究。先知道,后面整体理解
	@Nullable
	private Set<ApplicationListener<?>> earlyApplicationListeners;

	/** ApplicationEvents published before the multicaster setup. */
	// 在多播器设置之前发布的ApplicationEvents
	@Nullable
	private Set<ApplicationEvent> earlyApplicationEvents;


	/**
	 * Create a new AbstractApplicationContext with no parent.
	 * 创建一个没有父级的新AbstractApplicationContext,这里指定了资源加载器
	 */
	public AbstractApplicationContext() {
   
		this.resourcePatternResolver = getResourcePatternResolver();
	}

	/**
	 * Create a new AbstractApplicationContext with the given parent context.
	 * 使用给定的父上下文创建一个新的AbstractApplicationContext。
	 * @param parent the parent context
	 */
	public AbstractApplicationContext(@Nullable ApplicationContext parent) {
   
		this();
		setParent(parent);
	}

2.3.1 ConfigurableEnvironment 介绍

在这里插入图片描述

上图就是环境变量结构,Spring提供了一套环境配置标准,大多数需要配置环境的都将实现该接口。至于该接口的到底规定哪些东西。
在这里插入图片描述

看到这个结构是不是有种似曾相识的感觉,你看ioc的整体设计,红框内的。这就是Spring的整体架构思想。

  • 定义基础接口规范
  • 定义很多拓展接口实现基础接口
  • 定义一个接口来集合所有的拓展接口
  • 定义一个配置接口
  • 定义一个抽象实现类,这个抽象实现了就是开发用的基础了,要实现继续拓展,然后继承该类就行

在阅读源码时,完全可以照着这个顺序去解析,有助于把我整体性。

Spring的设计是有这个规律的,整体架构的规律是这样。提供拓展点,在哪个层次都可以拓展,提供高定制性。如果不满足Spring提供的,我们可以继承最初的接口规范,一层一层的进行拓展。如果想要在他的设计上完善,更具需求的在不同的层次接入拓展。在以后的设计解决方案是,可以参考。我看的源码整体架构不是很多,比较不出优劣,等以后积累一定程度在说,但是Spring的思想是可以借鉴的。

public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
   

	/**
	 * Specify the set of profiles active for this {@code Environment}. Profiles are
	 * evaluated during container bootstrap to determine whether bean definitions
	 * should be registered with the container.
	 * <p>Any existing active profiles will be replaced with the given arguments; call
	 * with zero arguments to clear the current set of active profiles. Use
	 * {@link #addActiveProfile} to add a profile while preserving the existing set.
	 * ~~~~~~~~~~~~~~~~~~~~~~~
	 * 中文解释
	 * 指定为此Environment激活的配置文件集。
	 * ~~~~~~~~~~~~~~~~~~~~~~~
	 * @throws IllegalArgumentException if any profile is null, empty or whitespace-only
	 * @see #addActiveProfile
	 * @see #setDefaultProfiles
	 * @see org.springframework.context.annotation.Profile
	 * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
	 */
	void setActiveProfiles(String... profiles);

	/**
	 * Add a profile to the current set of active profiles.
	 * ~~~~~~~~~~~~~~~~
	 * 中文解释:
	 * 在当前激活文件集中增加配置文件
	 * ~~~~~~~~~~~~~~~~
	 * @throws IllegalArgumentException if the profile is null, empty or whitespace-only
	 * @see #setActiveProfiles
	 */
	void addActiveProfile(String profile);

	/**
	 * Specify the set of profiles to be made active by default if no other profiles
	 * ~~~~~~~~~~~~~~
	 * 中文解释:
	 * 如果没有通过setActiveProfiles显式激活其他配置文件,则指定默认情况下将其激活的配置文件集
	 * ~~~~~~~~~~~~~~
	 * are explicitly made active through {@link #setActiveProfiles}.
	 * @throws IllegalArgumentException if any profile is null, empty or whitespace-only
	 * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
	 */
	void setDefaultProfiles(String... profiles);

	/**
	 * Return the {@link PropertySources} for this {@code Environment} in mutable form,
	 * allowing for manipulation of the set of {@link PropertySource} objects that should
	 * be searched when resolving properties against this {@code Environment} object.
	 * The various {@link MutablePropertySources} methods such as
	 * ~~~~~~~~~~~~~~~~~~~
	 * 以可变形式返回此Environment的PropertySources ,
	 * 从而允许处理在针对该Environment对象解析属性时应搜索的PropertySource对象集。 
	 * 各种MutablePropertySources方法
	 * (例如addFirst , addLast , addBefore和addAfter允许对属性源顺序进行细粒度控制。
	 *  例如,这在确保某些用户定义的属性源具有优先于默认属性源
	 * (例如系统属性集或系统环境变量集)的搜索优先级时很有用
	 * ~~~~~~~~~~~~~~~~~~~
	 * 其实我是没有理解这个是什么作用,意思就是说返回一个可变的环境属性,提供各种方法来操作配置属性优先级。
	 * 这里姑且算是,设置谁先执行,谁先生效
	 * ~~~~~~~~~~~~~~~~~~~
	 * {@link MutablePropertySources#addFirst addFirst},
	 * {@link MutablePropertySources#addLast addLast},
	 * {@link MutablePropertySources#addBefore addBefore} and
	 * {@link MutablePropertySources#addAfter addAfter} allow for fine-grained control
	 * over property source ordering. This is useful, for example, in ensuring that
	 * certain user-defined property sources have search precedence over default property
	 * sources such as the set of system properties or the set of system environment
	 * variables.
	 * @see AbstractEnvironment#customizePropertySources
	 */
	MutablePropertySources getPropertySources();

	/**
	 * Return the value of {@link System#getProperties()} if allowed by the current
	 * {@link SecurityManager}, otherwise return a map implementation that will attempt
	 * to access individual keys using calls to {@link System#getProperty(String)}.
	 * <p>Note that most {@code Environment} implementations will include this system
	 * properties map as a default {@link PropertySource} to be searched. Therefore, it is
	 * recommended that this method not be used directly unless bypassing other property
	 * sources is expressly intended.
	 * <p>Calls to {@link Map#get(Object)} on the Map returned will never throw
	 * ~~~~~~~~~~~~~~~~~~~~~~
	 * 中文解释:
	 * 如果当前SecurityManager允许,返回System.getProperties()的值,
	 * 否则返回一个映射实现,该实现将尝试使用对System.getProperty(String)调用来访问各个键
	 * 请注意,大多数Environment实施都将包含此系统属性映射,作为要搜索的默认PropertySource 。 
	 * 因此,建议不要直接使用此方法,除非明确打算绕过其他属性源。
	 * 在返回的Map上调用Map.get(Object)永远不会抛出IllegalAccessException ; 
	 * 如果SecurityManager禁止访问属性,则将返回null并发出INFO级别的日志消息,指出该异常
	 * ~~~~~~~~~~~~~~~~~~~~~~
	 * 通过getSecurityManager()获取SecurityManager来判断是否被允许获取系统属性
	 * ~~~~~~~~~~~~~~~~~~~~~~
	 * {@link IllegalAccessException}; in cases where the SecurityManager forbids access
	 * to a property, {@code null} will be returned and an INFO-level log message will be
	 * issued noting the exception.
	 */
	Map<String, Object> getSystemProperties();

	/**
	 * Return the value of {@link System#getenv()} if allowed by the current
	 * {@link SecurityManager}, otherwise return a map implementation that will attempt
	 * to access individual keys using calls to {@link System#getenv(String)}.
	 * <p>Note that most {@link Environment} implementations will include this system
	 * environment map as a default {@link PropertySource} to be searched. Therefore, it
	 * is recommended that this method not be used directly unless bypassing other
	 * property sources is expressly intended.
	 * <p>Calls to {@link Map#get(Object)} on the Map returned will never throw
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * 如果当前SecurityManager允许,返回System.getenv()的值,
	 * 否则返回一个映射实现,该实现将尝试使用对System.getenv(String)调用来访问各个键。
	 * 请注意,大多数Environment实现都将包含此系统环境映射作为要搜索的默认PropertySource 。 
	 * 因此,建议不要直接使用此方法,除非明确打算绕过其他属性源。
	 * 在返回的Map上调用Map.get(Object)永远不会抛出IllegalAccessException ; 
	 * 如果SecurityManager禁止访问属性,则将返回null并发出INFO级别的日志消息,指出该异常
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * {@link IllegalAccessException}; in cases where the SecurityManager forbids access
	 * to a property, {@code null} will be returned and an INFO-level log message will be
	 * issued noting the exception.
	 */
	Map<String, Object> getSystemEnvironment();

	/**
	 * Append the given parent environment's active profiles, default profiles and
	 * property sources to this (child) environment's respective collections of each.
	 * <p>For any identically-named {@code PropertySource} instance existing in both
	 * parent and child, the child instance is to be preserved and the parent instance
	 * discarded. This has the effect of allowing overriding of property sources by the
	 * child as well as avoiding redundant searches through common property source types,
	 * e.g. system environment and system properties.
	 * <p>Active and default profile names are also filtered for duplicates, to avoid
	 * confusion and redundant storage.
	 * <p>The parent environment remains unmodified in any case. Note that any changes to
	 * the parent environment occurring after the call to {@code merge} will not be
	 * reflected in the child. Therefore, care should be taken to configure parent
	 * property sources and profile information prior to calling {@code merge}.
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * 将给定的父环境的活动配置文件,默认配置文件和属性源追加到此(子)环境各自的集合中。
	 * 对于父代和子代中都存在的任何名称相同的PropertySource实例,将保留子代实例,并丢弃父代实例。 
	 * 这样的效果是允许子级覆盖属性源,并避免通过常见属性源类型(例如系统环境和系统属性)进行冗余搜索。
	 * 活动和默认配置文件名称也会被过滤,以防重复,以避免混淆和冗余存储。
	 * 在任何情况下,父环境都保持不变。 
	 * 请注意,在merge调用之后对父环境所做的任何更改都不会反映在子项中。 
	 * 因此,在调用merge之前,应谨慎配置父​​属性源和配置文件信息
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * 默认情况下父环境的配置文件遗传到子环境配置文件,单是出现两者同名的配置文件,
	 * 子类还是用自己的配置文件,而不是用父环境的配置文件,就近原则。
	 * 在调用这个方法merge()之前父配置文件的更改是会同步到子环境中,但是这个方法的地调用,
	 * 这种特性就消失了,子环境自己玩,不受到付环境的影响。
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * @param parent the environment to merge with
	 * @since 3.1.2
	 * @see org.springframework.context.support.AbstractApplicationContext#setParent
	 */
	void merge(ConfigurableEnvironment parent);

上面的方法中文翻译我借助的谷歌翻译,在加上自己的理解。具体的用处,这种辅助的,需要在应用中慢慢理解,IOC的设计中一定会用到,到时候在提及。

2.4 实现ApplicationContext接口

下面这些方法就没必要介绍了,如方法名可知道。之前对ApplicationContext的认识得知,该接口有对基础属性的get方法,下面就是这些方法的实现。

		@Override
	public void setId(String id) {
   
		this.id = id;
	}

	@Override
	public String getId() {
   
		return this.id;
	}

	@Override
	public String getApplicationName() {
   
		return "";
	}

	/**
	 * Set a friendly name for this context.
	 * Typically done during initialization of concrete context implementations.
	 * <p>Default is the object id of the context instance.
	 */
	public
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值