这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战java
上一篇讲了spring容器初始化流程中的beanFactory预处理。那这一篇将对beanFactory的后置处理进行整理。web
其实spring的启动过程是有不少流程的,也是很复杂的,我只是根据本身的思路和理解来进行整理的,确定就会忽略一些自认为不重要的或者是本身没有发现的地方。也但愿xdjmm可以多多指正。spring
依赖的pom:springboot
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
复制代码
本篇文章将要说的一个流程就是:markdown
//所在类及方法: AbstractApplicationContext#refresh
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
复制代码
进入postProcessBeanFactory方法,发现该方法是一个空方法,什么也没作,不过根据该方法的注释翻译:session
/** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for registering special * BeanPostProcessors etc in certain ApplicationContext implementations. * @param beanFactory the bean factory used by the application context */
// 在beanFactory完成标准的初始化后修改应用上下文的内部bean factory,全部的bean定义都会被加载,可是并不会实例化bean。这里容许注册特殊的
// BeanPostProcessors 等在某些应用上下文中(ApplicationContext的实现)
复制代码
从注释能够知道,postProcessBeanFactory就是对BeanFactory进行后置处理,也就是在BeanFactory完成初始化后能够对其进行一些修改,具体要作什么,就看子类怎么去实现的了。 因为我只导入了spring-context包,里面对该方法的实现是没有的,不过能够在springboot项目中去查看该方法在子类中是如何去实现的。 这里须要注意的是,我使用的springboot的版本是2.5.2,不一样版本的代码多是不同的。 下面对其中的一个子类代码进行讲解:app
// 所在类及方法:AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用父类的postProcessBeanFactory方法
super.postProcessBeanFactory(beanFactory);
// 执行scanner和reader 在此地方打断点,发现第二步并无执行。
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
复制代码
AnnotationConfigServletWebServerApplicationContext的父类是ServletWebServerApplicationContext, 下面看看父类中的postProcessBeanFactory方法是怎么样的。ide
// 所在类及方法:ServletWebServerApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 向BeanFactory中注册一个PostProcessor
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
// 调用registerWebApplicationScopes
registerWebApplicationScopes();
}
复制代码
在父类的方法中主要就是作了两件事:源码分析
类的注释:post
/**
* Variant of {@link ServletContextAwareProcessor} for use with a
* {@link ConfigurableWebApplicationContext}. Can be used when registering the processor
* can occur before the {@link ServletContext} or {@link ServletConfig} have been
* initialized.
*/
// 用于ConfigurableWebApplicationContext的一个ServletContextAwareProcessor扩展,
// 能够在初始化ServletContext或ServletConfig以前进行处理器的注册。
复制代码
注解中说明了是ServletContextAwareProcessor,那么看看ServletContextAwareProcessor类的注释:
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
* implementation that passes the ServletContext to beans that implement
* the {@link ServletContextAware} interface.
*
* <p>Web application contexts will automatically register this with their
* underlying bean factory. Applications do not use this directly.
*/
// 将ServletContext传递给实现ServletContextAware接口的bean
//Web应用程序上下文将自动将其注册到底层bean工厂。应用程序不会直接使用它
复制代码
ServletContextAwareProcessor实现了BeanPostProcessor接口, 那么这里就定位至他的postProcessBeforeInitialization方法和postProcessAfterInitialization方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
复制代码
代码也比较简单,就是判断当前bean是ServletContextAware的实现仍是ServletConfigAware的实现,而后分别转换后再调用各自接口的实现方法。 ServletContextAware的实现类就是调用setServletContext方法。 ServletConfigAware的实现类就是调用setServletConfig方法。
扩展: 这里涉及到了BeanPostProcessor和XXXAware接口,这两种接口的基本使用这里就不细说了; 这里的大概流程就是:向容器注册BeanPostProcessor的一个实现,而后该实现类是处理XXXAware接口的实现类实现的方法。 其实本身也能够根据这个模板来进行自定义XXXAware接口的扩展,固然也能够进行其余的一些处理,总之就是BeanPostProcessor提供了很好的扩展性,这里只是其中的一种方式。
这个方法主要就是向beanFactory中注册做用域:("request", "session", "globalSession", "application"),在源码分析:
该方法的源码以下:
// 所在类及方法:ServletWebServerApplicationContext#registerWebApplicationScopes
private void registerWebApplicationScopes() {
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
existingScopes.restore();
}
复制代码
ExistingWebApplicationScopes是ServletWebServerApplicationContext类中的一个静态类。源码以下:
public static class ExistingWebApplicationScopes {
static {
Set<String> scopes = new LinkedHashSet<>();
scopes.add(WebApplicationContext.SCOPE_REQUEST);
scopes.add(WebApplicationContext.SCOPE_SESSION);
SCOPES = Collections.unmodifiableSet(scopes);
}
// 这是构造方法,大概就是根据SCOPES获取beanFactory中已经注册的scope,而后放入scopes
// 须要注意的是,在上面的方法中,第二行才在向beanFactory中注册,也就是这时的beanFactory里面没有request和session这两个scop
// 因此这里就完成了beanFactory的赋值。建议打断点进去看看
public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
for (String scopeName : SCOPES) {
Scope scope = beanFactory.getRegisteredScope(scopeName);
if (scope != null) {
this.scopes.put(scopeName, scope);
}
}
}
// 因为上面的方法并无值存入scopes,因此这里也就没执行里面的内容
public void restore() {
this.scopes.forEach((key, value) -> {
if (logger.isInfoEnabled()) {
logger.info("Restoring user defined scope " + key);
}
this.beanFactory.registerScope(key, value);
});
}
}
复制代码
WebApplicationContextUtils.registerWebApplicationScopes(),这个方法就是向beanFactory注册web的scope了,源码以下:
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
registerWebApplicationScopes(beanFactory, null);
}
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) {
// 注册做用域
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// 注册request SCOP
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());// 注册session SCOP
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // 注册application SCOP
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 添加依赖项
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
复制代码
这个方法也比较简单,主要注册了几种注册域request ,session ,application。
至此,org.springframework.context.support.AbstractApplicationContext.postProcessBeanFactory 这个方法的大概流程就讲完了,这个方法主要就是作了两点: