栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

一篇文章彻底搞懂spring的ApplicationContext体系

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一篇文章彻底搞懂spring的ApplicationContext体系

本文主要介绍ApplicationContext在Spring中各个子类的作用和区别

一、ApplicationContext子类体系图

从图中我们可以得到两个重要信息:

  1. ApplicationContext的子类都是继承自AbstractApplicationContext
  2. AbstractApplicationContext的子类分为两类,一类是GenericApplicationContext的子类,一类是AbstractRefreshableApplicationContext的子类.

接下来我们沿着这两个特点进行分析

1.1.AbstractApplicationContext 1.1.1.作用介绍

我们先来看下源码中的注释对ApplicationContext作用的定位:

 
  1. AbstractApplication是对ApplicationContext接口的一个抽象实现类,它不持有任何配置,仅仅是对公共上下文功能的实现.使用模版方法设计模式,需要子类实现其抽线方法
  2. 与BeanFactory相比,ApplicationContext的作用是检测内部Bean工厂的特殊bean的定义,因此它会有以下操作:
    1. 自动把BeanFactoryPostProcessors、BeanPostProcessors、ApplicationListeners注册成bean
    2. 在context中以bean的形式提供MessageSource,bean名称为messageSource
    3. 在context中以bean的形式提供ApplicationEventMulticaster,bean名称为applicationEventMulticaster,并提供默认实现SimpleApplicationEventMulticaster
  3. 通过继承DefaultResourceLoader来实现资源加载功能

接下来我们来看下AbstractApplicationContext具体做了哪些工作

1.1.2.AbstractApplicationContext功能 1.1.2.1.对ApplicationContext接口的实现 1.1.2.1.1.对ApplicationContext接口本身定义的实现

ApplicationContext接口定义:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
	@Nullable
	String getId();
	String getApplicationName();
	String getDisplayName();
	long getStartupDate();
	@Nullable
	ApplicationContext getParent();
	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

AbstractApplicationContext通过持有对应属性值来实现:

	private String id = ObjectUtils.identityToString(this);
	private String displayName = ObjectUtils.identityToString(this);
	private ApplicationContext parent;
	private long startupDate;
  1. 其中ApplicationName默认为空
  2. getAutowireCapableBeanFactory通过抽象方法getBeanFactory有子类实现,
1.1.2.1.2.对ApplicationContext父接口EnvironmentCapable的实现

AbstractApplicationContext 定义了一个ConfigurableEnvironment属性:

private ConfigurableEnvironment environment;

ConfigurableEnvironment 里面持有当前应用yml文件中所用变量信息.

使用方法:

application.yml配置:

app.name: springmvc

1.通过ConfigurableEnvironment获取:

在ApplicationContext中定义的ConfigurableEnvironment,实际的子类是StandardEnvironment.

@SpringBootApplication
public class SpringMvcApp {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);
        StandardEnvironment standardEnvironment = (StandardEnvironment) context.getEnvironment();
        String appName = standardEnvironment.getProperty("app.name");
        System.out.println("appName:"+appName);
    }
}

appName:springmvc

2.占位符获取

@Service
public class UserServiceImpl implements UserService , InitializingBean {

    @Value("${app.name}")
    private String appName;
  
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("占位符获取appName:"+appName);
    }
}
1.1.2.1.2.对ApplicationContext父接口ApplicationEventPublisher的实现
public interface ApplicationEventPublisher {

	default void publishEvent(ApplicationEvent event) {
		publishEvent((Object) event);
	}
	
	void publishEvent(Object event);

}

ApplicationEventPublisher接口是发送容器事件的接口,通过观察者模式实现,会在容器不同阶段发送不同的ApplicationEvent.

AbstractApplicationContext在refresh函数中会调用initApplicationEventMulticaster初始化一个ApplicationEventMulticaster,默认子类为:SimpleApplicationEventMulticaster,用于发送ApplicationEvent和管理当前应用中注册的ApplicationListener.

你也可以定义自己的ApplicationEventMulticaster,设置bean名称为applicationEventMulticaster,就可以替换默认的实现.

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

我们来看下ApplicationEventMulticaster工作原理:

既然ApplicationEventMulticaster是通过观察者模式来实现ApplicationEvent的广播,那么ApplicationEventMulticaster的实现中一定会持有一组观察者,即一组ApplicationListener的实现.

果然在AbstractApplicationEventMulticaster,定义了一个ListenerRetriever,而这个ListenerRetriever就持有一组ApplicationListener.

public abstract class AbstractApplicationEventMulticaster
		implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {

	private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
  
}


private class ListenerRetriever {
  ...
		public final Set> applicationListeners;
  ...
}

AbstractApplicationEventMulticaster提供了添加、删除和获取ApplicationListener的功能.这里不在粘贴AbstractApplicationEventMulticaster的源码.

我们看下SimpleApplicationEventMulticaster是如何广播ApplicationEvent事件的.

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Nullable
	private Executor taskExecutor;

	@Nullable
	private ErrorHandler errorHandler;
	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}
  
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"unchecked", "rawtypes"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}
	
	
	}

从multicastEvent函数可以看出,SimpleApplicationEventMulticaster在广播ApplicationEvent事件时有两种策略:

  1. 设置了线程池,则将广播ApplicationEvent的任务提交到线程池异步执行
  2. 没有设置线程池,则同步执行广播ApplicationEvent的任务
1.1.2.1.3.对ApplicationContext父接口BeanFactory、ListableBeanFactory、HierarchicalBeanFactory的实现

AbstractApplicationContext对BeanFactory、ListableBeanFactory、HierachicalBeanFactory的实现,都通过抽象方法getBeanFactory获得子类持有的ConfigurableListableBeanFactory来实现这三个BeanFactory的功能,AbstractApplicationContext充当了一个代理的角色.

1.1.2.1.4.对ApplicationContext父接口MessageSource的实现

MessageSource是spring对国际化的实现,这里不详细介绍,后面会有文章详细介绍其原理.

1.1.2.1.5.对ApplicationContext父接口ResourcePatternResolver的实现

ResourcePatternResolver提供了根据路径查找对应资源文件的功能.

public interface ResourcePatternResolver extends ResourceLoader {

	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

	Resource[] getResources(String locationPattern) throws IOException;

}

AbstractApplicationContext中不具体实现其功能,而是充当代理者的角色,具体实现有PathMatchingResourcePatternResolver完成.

PathMatchingResourcePatternResolver主要解析classpath路径下的文件

1.1.2.2.对ConfigurableApplicationContext接口的实现

AbstractApplicationContext最重要的实现.

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	
  
  void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

  
	void addApplicationListener(ApplicationListener listener);

  
	void addProtocolResolver(ProtocolResolver resolver);

  
	void refresh() throws BeansException, IllegalStateException;

  
	void registerShutdownHook();

  
	@Override
	void close();

  
	boolean isActive();

  
	ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

ConfigurableApplicationContext的作用?

ConfigurableApplicationContext 重点在于设置应用的相关组件,而ApplicationContext接口重点在于获取配置.

下面主要看下refresh函数,该函数定义了context初始化的主要流程,其中就包括初始化容器中bean的主流程.

我们看下refresh函数做了哪些工作?

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

prepareRefresh阶段

该阶段主要设置启动时间和启动标识,可以被子类覆盖,但覆盖逻辑里面一定要调用super.prepareRefresh();

obtainFreshBeanFactory阶段

获取子类持有的BeanFactory.

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

refreshBeanFactory()是一个抽象函数,只有当前ApplicationContext是AbstractRefreshableApplicationContext的子类时才有具体逻辑,如下:

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

如果当前ApplicationContext已经持有了BeanFactory实例,那么重新销毁所有的bean,并重新加载,相当于每次返回一个新的BeanFactory实例.

prepareBeanFactory阶段

配置BeanFactory设置内置的Bean和相关配置如classloader、el表达式解析器等

postProcessBeanFactory阶段

这时Beanfactory已经初始化完成,所有的bean definition已加载,但是还未实例bean,允许AbstractApplication的子类对BeanFactory进行修改,

如注册BeanPostProcessors.

invokeBeanFactoryPostProcessors阶段

实例化并执行所有BeanFactoryPostProcessor的bean,如有设置了顺序,则按顺序执行.

在springboot应用中,在这个过程开始ConfigurationClassPostProcessor来扫描用户系统的class,并将其转化成Bean definition注册到BeanFactory中.

registerBeanPostProcessors阶段

实例化所有的BeanPostProcessor ,并注册

initMessageSource阶段

初始化国际化相关配置

initApplicationEventMulticaster阶段

设置ApplicationEvent广播控制器

onRefresh阶段

模版方法,可以用于初始化特殊的bean

registerListeners阶段

注册ApplicationListener,用于监听ApplicationEventMulticaster广播的ApplicationEvent事件

finishBeanFactoryInitialization阶段-bean生命周期开始阶段

这个阶段才开始将剩余的Bean进行初始化,用户设置的非懒加载的bean都在这阶段完成.

如@Controller、@Service、@Compenont等修饰的.

finishRefresh阶段

ApplicationContext refresh流程完成,容器初始化完成,做以下工作

  • 发送ContextRefreshedEvent事件
  • 删除Context -level 缓存,如扫描到的类信息
  • 注册LifecycleProcessor,并执行onRefresh方法
1.1.2.5.对Lifecycle接口的实现

生命周期接口,没有看到在哪里使用到.

public interface Lifecycle {


	void start();

	void stop();

	boolean isRunning();

}
1.2GenericApplicationContext和AbstractRefreshableApplicationContext对比 1.2.1.继承关系对比

先贴两张图,看下两者的继承关系:

GenericApplicationContext继承关系

AbstractRefreshableApplicationContext继承关系

从继承关系上看GenericeApplicationContext实现了BeanDefinitionRegistry接口,BeanDefinitionRegistry 有什么作用:

public interface BeanDefinitionRegistry extends AliasRegistry {

	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	boolean containsBeanDefinition(String beanName);
  
	String[] getBeanDefinitionNames();

	int getBeanDefinitionCount();

	boolean isBeanNameInUse(String beanName);

}

BeanDefinitionRegistry提供了注册Bean Definition的功能,当前其子类的实现也会持有这些Bean Definitions.

1.2.2.AbstractApplicationContext抽象方法实现对比

GenericApplicationContext

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
...
	@Override
	protected final void refreshBeanFactory() throws IllegalStateException {
		if (!this.refreshed.compareAndSet(false, true)) {
			throw new IllegalStateException(
					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
		}
		this.beanFactory.setSerializationId(getId());
	}
	...

}

AbstractRefreshableApplicationContext

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

	protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;
}

GenericApplicationContext和AbstractRefreshableApplicationContext在实现AbstractApplicationContext的refreshBeanFactory有区别:

  1. GenericApplicationContext 没有做任何动作,只是判断了一下当前refresh的次数,最多只能一次.
  2. AbstractRefreshableApplicationContext:每次refresh都会重新生成BeanFactory,并重新加载Bean,加载bean definitions通过loadBeanDefinitions抽象方法,尤其子类实现.

总结:

  1. GenericApplicationContext子类只会调用一次refresh过程,并且可以由其他组件向它组册Bean Definition
  2. AbstractRefreshableApplicationContext支持多次refresh,但是需要子类提供bean配置地址
二、GenericApplicationContext子类分析

我们先来看下GenericeApplicationContext有哪些子类,然后逐个介绍:

2.1GenericWebApplicationContext和其子类

GenericWebApplicationContext对在web环境下GenericApplicationContext实现.

有以下功能:

  1. 可以基于编程配置web相关信息,而不是传统的web.xml.
  2. web相关的配置通过WebApplicationInitializer在tomcat启动后,调用onStartup方法配置servlet/filter/listener等信息.
  3. 添加ThemeSource bean,用于web环境的主题切换

ServletWebServerApplicationContext

ServletWebServerApplicationContext是GenericWebApplicationContext的直接子类,相比于GenericWebApplicationContext,

ServletWebServerApplicationContext增加了创建、初始化一个web server的功能.

	@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}
	
	
	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context",
						ex);
			}
		}
		initPropertySources();
	}

ServletWebServerApplicationContext是可以面向开发者直接使用的一个web 类型的ApplicationContext,但是spring提供了更好的选择.

AnnotationConfigServletWebServerApplicationContext和XmlServletWebServerApplicationContext.

AnnotationConfigServletWebServerApplicationContext

该context可以根据一个配置了配置文件路径也是扫描bean的路径或包名的@Configuration类,来初始化我们的应用,完成bean的加载等.

在springboot中

@SpringBootApplication
public class SpringMvcApp {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);
        
    }
}

SpringApplication.run返回的ApplicationContext 实际就是AnnotationConfigServletWebServerApplicationContext

XmlServletWebServerApplicationContext

相比于AnnotationConfigServletWebServerApplicationContext通过注解方式配置bean的配置文件、资源文件,XmlServletWebServerApplicationContext是通过提供相应的构造函数传入文件路径或者通过load方法加载相应的资源文件.

public class XmlServletWebServerApplicationContext
		extends ServletWebServerApplicationContext {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public XmlServletWebServerApplicationContext() {
		this.reader.setEnvironment(this.getEnvironment());
	}

	public XmlServletWebServerApplicationContext(Resource... resources) {
		load(resources);
		refresh();
	}

	public XmlServletWebServerApplicationContext(String... resourceLocations) {
		load(resourceLocations);
		refresh();
	}
	public XmlServletWebServerApplicationContext(Class relativeClass,
			String... resourceNames) {
		load(relativeClass, resourceNames);
		refresh();
	}

	public void setValidating(boolean validating) {
		this.reader.setValidating(validating);
	}


	public final void load(Resource... resources) {
		this.reader.loadBeanDefinitions(resources);
	}

	public final void load(String... resourceLocations) {
		this.reader.loadBeanDefinitions(resourceLocations);
	}


	public final void load(Class relativeClass, String... resourceNames) {
		Resource[] resources = new Resource[resourceNames.length];
		for (int i = 0; i < resourceNames.length; i++) {
			resources[i] = new ClassPathResource(resourceNames[i], relativeClass);
		}
		this.reader.loadBeanDefinitions(resources);
	}

}

加载资源的方式:

  • 构造函数传入
  • 调用load方法
2.2.AnnotationConfigApplicationContext和GenericXmlApplicationContext

AnnotationConfigApplicationContext/GenericXmlApplicationContext同AnnotationConfigServletWebServerApplicationContext/XmlServletWebServerApplicationContext类似

  • AnnotationConfigApplicationContext是通过@Configuration类来加载资源文件,初始化当前ApplicationContext的.
  • GenericXmlApplicationContext通过特定文件加载资源

不同的是:AnnotationConfigApplicationContextAnnotationConfigApplicationContext/GenericXmlApplicationContext是非web的ApplicationContext,AnnotationConfigServletWebServerApplicationContext/XmlServletWebServerApplicationContext是支持web服务的context,可以提供对外的web服务.

假如你要写一个tcp服务,可以用这两者中的一个作为你管理bean的容器,只不过你需要自己在AbstractApplicationContext.refresh执行的某一个步骤或其他时机,完成自己的端口监听等.

或者,当前你的服务不需要对外提供服务,你也可以选择该这两个context.

2.3.StaticApplicationContext和其子类

StaticApplicationContext和StaticWebApplicationContext不会扫描任何文件,而是通过相应的方法直接注册bean,一般用于测试.

2.4.GenericGroovyApplicationContext

GenericGroovyApplicationContext提供了spring对Groovy的支持,可以加载Groovy bean definition,并完成bean的注册.

2.5.GenericReactiveWebApplicationContext和其子类

GenericReactiveWebApplicationContext和ReactiveWebServerApplicationContext同GenericWebApplicationContext和ServletWebServerApplicationContext功能类似,只不过是对reactive环境的支持.

  • GenericReactiveWebApplicationContext不会启动一个web server,资源路径使用相对路径
  • ReactiveWebServerApplicationContext启动一个webserver
二、AbstractRefreshableApplicationContext子类分析

AbstractRefreshableApplicationContext体系基本上和GenericApplicationContext类似,它们最本质的区别就是:

在refreshBeanFactory阶段AbstractRefreshableApplicationContext体系的ApplicationContext会返回一个新的BeanFactory,并重新加载bean.

而GenericApplicationContext体系的ApplicationContext会一直使用refresh前创建的BeanFactory.

AbstractRefreshableApplicationContext的好处是可以执行多次refresh.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/884942.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号