文章目录

  • ​​postProcessBeanFactory作用​​
  • ​​源码分析​​
  • ​​详解一获取ServletRequest的线程安全问题​​
  • ​​详解一scanner.scan(this.basePackages);​​
  • ​​详解一reader.register(ClassUtils.toClassArray(this.annotatedClasses));​​
  • ​​demo​​
  • ​​总结:​​

postProcessBeanFactory作用

  • AbstractApplicationContext并没有任何实现,但其允许在上下文子类中重写
  • 其方法的注释翻译如下: 在beanfactory加载完毕后,尚未构建BeanDefinition和实例化bean之前,允许子类覆写ApplicationContext来实现相关功能,例如: 修改BeanFactory 或者注册BeanPostProcessor等等
  • spring并没有约束子类重写后具体的实现方向,只是告知当前的被执行时机是beanFactory加载完成,BeanDefinition加载和bean实例化尚未开始

源码分析

本文着重分析AnnotationConfigServletWebServerApplicationContext.postProcessBeanFactory
1 主要完成bean的作用域的扩充以及相关web特定四个对象的创建加载方式
2 其次在通过scan和register完成注解扫描加载BD,通过springboot的启动方式这里basePackages和annotatedClasses都为空不会执行
3 需要注意scanner只能完成@Component@Service@Controller@Repository的加载不可完成@Import等注解的加载

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
1 调用父类的postProcessBeanFactory
super.postProcessBeanFactory(beanFactory);
2 如果有扫描包 交给ClassPathBeanDefinitionScanner完成BeanDefinition加载
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
3 如果有注册类 交给ClassPathBeanDefinitionScanner完成BeanDefinition加载
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}

父类主要完成ServletContextAware 和ServletConfigAware的功能以及 ServletRequest ServletResponse HttpSession WebRequest的注入问题

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
1.1完成对ServletContextAware 和ServletConfigAware的aware功能
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));

ServletContextAware的注入交给ServletContextAwareProcessor处理 这里可以参见第三篇对ignoreDependencyInterface的解释
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
1.2注册Bean的相关作用域 web环境除去单例,原型,扩充了请求 会话 应用级别
registerWebApplicationScopes();
}

registerWebApplicationScopes 主要交给WebApplicationContextUtils.registerWebApplicationScopes

  • 关键点一:注册bean作用域scope(request session application)
  • 关键点二: registerResolvableDependency (ServletRequest,ServletResponse,HttpSession,WebRequest) 当使用了ServletRequest例如httpservletRequest等实例,是可以通过spring容器获取
  • ServletRequest交由RequestObjectFactory.getObject 其内部通过ThreadLocal获取,解决线程安全问题
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {

1.2.1完成scope的注册
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}

1.2.2 registerResolvableDependency的作用参见第三章 完成ServletRequest等相关类的创建工厂加载
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);
}
}

详解一获取ServletRequest的线程安全问题

虽然每次调用getObject,但内部实现调用threadlocal,所以注入时不会出现两个请求使用同一个request问题

private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {

@Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
@Override
public String toString() {
return "Current HttpServletRequest";
}
}
private static ServletRequestAttributes currentRequestAttributes() {
// RequestContextHolder内部采用ThreadLocal实现
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
if (!(requestAttr instanceof ServletRequestAttributes)) {
throw new IllegalStateException("Current request is not a servlet request");
}
return (ServletRequestAttributes) requestAttr;
}

详解一scanner.scan(this.basePackages);

完成basePackages 扫描生成BeanDefinition;
  • 通过将相关包下所有class文件解析成Resource
  • 解析所有的resource查出有@Component等注解的类
  • 生成ScannedGenericBeanDefinition
  • 为BeanDefinition处理@Lazy @Primary 等注解
  • 将所有的bd注册到beanDefinitionMap

详解一reader.register(ClassUtils.toClassArray(this.annotatedClasses));

完成annotatedClasses加载生成BeanDefinition
  • 为指定类创建BeanDefinition,注册到beanDefinitionMap

demo

当我们采用如下方式启动spring容器 则postProcessBeanFactory内部scanner.scan和reader.register会工作

AnnotationConfigServletWebServerApplicationContext applicationContext = new AnnotationConfigServletWebServerApplicationContext();
applicationContext.register(Demo.class);
applicationContext.scan("com.renxl.package");
applicationContext.refresh();

总结:

  • AnnotationConfigServletWebServerApplicationContext.postProcessBeanFactory 主要完成了特定四个bean(ServletRequest,ServletResponse,HttpSession,WebRequest)注入问题,以及ServletContextAware
  • AnnotationConfigServletWebServerApplicationContext.postProcessBeanFactory 在执行时有可能会处理注解加载问题,但springboot启动不会执行,如果需要执行参见demo,
  • 在下文实际加载BeanDefinition的地方详解其内部实现