spring核心源码分析第五篇 refresh流程之postProcessBeanFactory
原创
©著作权归作者所有:来自51CTO博客作者ren5201313的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
- 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的地方详解其内部实现