经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring?refresh()源码解析
来源:jb51  时间:2023/3/15 8:52:46  对本文有异议

正文

  1. public void refresh() throws BeansException, IllegalStateException {
  2. synchronized(this.startupShutdownMonitor) {
  3. // 1. 初始化前的预处理
  4. this.prepareRefresh();
  5. // 2. 刷新Bean工厂
  6. ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
  7. // 3. BeanFactory的预处理配置
  8. this.prepareBeanFactory(beanFactory);
  9. try {
  10. // 4. BeanFactory的后置处理
  11. this.postProcessBeanFactory(beanFactory);
  12. // 5. 执行BeanFactory后置处理器
  13. this.invokeBeanFactoryPostProcessors(beanFactory);
  14. // 6. 注册Bean的后置处理器
  15. this.registerBeanPostProcessors(beanFactory);
  16. // 7. 初始化MessageSource
  17. this.initMessageSource();
  18. // 8. 初始化事件派发器
  19. this.initApplicationEventMulticaster();
  20. // 9. 子类的多态onRefresh
  21. this.onRefresh();
  22. // 10. 注册监听器
  23. this.registerListeners();
  24. // 11. 初始化所有剩下的单例Bean
  25. this.finishBeanFactoryInitialization(beanFactory);
  26. // 12. 完成容器的创建工作
  27. this.finishRefresh();
  28. } catch (BeansException var9) {
  29. if (this.logger.isWarnEnabled()) {
  30. this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
  31. }
  32. this.destroyBeans();
  33. this.cancelRefresh(var9);
  34. throw var9;
  35. } finally {
  36. // 13. 清除缓存
  37. this.resetCommonCaches();
  38. }
  39. }
  40. }

一、prepareRefresh:初始化前的预处理

  1. protected void prepareRefresh() {
  2. //设置容器启动时间
  3. this.startupDate = System.currentTimeMillis();
  4. //设置容器关闭状态为false
  5. this.closed.set(false);
  6. //设置容器激活状态为true
  7. this.active.set(true);
  8. if (this.logger.isDebugEnabled()) {
  9. if (this.logger.isTraceEnabled()) {
  10. this.logger.trace("Refreshing " + this);
  11. } else {
  12. this.logger.debug("Refreshing " + this.getDisplayName());
  13. }
  14. }
  15. //1.1初始化属性资源
  16. this.initPropertySources();
  17. //1.2校验
  18. this.getEnvironment().validateRequiredProperties();
  19. this.earlyApplicationEvents = new LinkedHashSet();
  20. }

1.1初始化属性值

初始化方法是个模压方法,由子类重写

  1. protected void initPropertySources() {
  2. }

Web容器GenericWebApplicationContext重写了此方法

  1. protected void initPropertySources() {
  2. //获取环境信息
  3. ConfigurableEnvironment env = getEnvironment();
  4. //判断是否是web配置环境
  5. if (env instanceof ConfigurableWebEnvironment) {
  6. ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
  7. }
  8. }

最终由StandardServletEnvironment进行初始化

  1. public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
  2. //使用web容器工具初始化
  3. WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
  4. }

把 Servlet 的一些初始化参数放入IOC容器中

  1. public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
  2. Assert.notNull(sources, "'propertySources' must not be null");
  3. String name = "servletContextInitParams";
  4. if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
  5. sources.replace(name, new ServletContextPropertySource(name, servletContext));
  6. }
  7. name = "servletConfigInitParams";
  8. if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
  9. sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
  10. }
  11. }

1.2属性校验

通过占位符解析器校验资源集合

  1. public void validateRequiredProperties() throws MissingRequiredPropertiesException {
  2. this.propertyResolver.validateRequiredProperties();
  3. }

这里的解析器作为常量在环境被实例化时就被创建出来的,PropertySourcesPropertyResolver是占位符解析器,将数据源中占位符替换成目标值

校验是否有需要被占位符修饰的属性,如果有但是资源中找不到对应属性的key就会抛出异常

  1. public void validateRequiredProperties() {
  2. MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
  3. for (String key : this.requiredProperties) {
  4. if (this.getProperty(key) == null) {
  5. ex.addMissingRequiredProperty(key);
  6. }
  7. }
  8. if (!ex.getMissingRequiredProperties().isEmpty()) {
  9. throw ex;
  10. }
  11. }

案例: 资源文件

  1. name=zhansan
  2. age=${name},10
  3. encoding=utf-8
  4. name2=${name}

测试代码

  1. @Test
  2. public void test1() throws Exception {
  3. //省略propertySources
  4. PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(getPropertySources());
  5. System.out.println(propertyResolver.getProperty("age"));
  6. System.out.println(propertyResolver.getProperty("encoding"));
  7. System.out.println(propertyResolver.resolvePlaceholders("must be encoding ${encoding}")); //输出must be encoding gbk
  8. }

输出结果

10,zhansan
utf-8
must be encoding utf-8

二、obtainFreshBeanFactory:刷新Bean工厂

  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  2. //2.1刷新Bean工厂
  3. refreshBeanFactory();
  4. return getBeanFactory();
  5. }

将容器刷新标识改为true,并且设置了工厂序列化id

  1. protected final void refreshBeanFactory() throws IllegalStateException {
  2. if (!this.refreshed.compareAndSet(false, true)) {
  3. throw new IllegalStateException(
  4. "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
  5. }
  6. this.beanFactory.setSerializationId(getId());
  7. }

三、prepareBeanFactory:Bean工厂预处理

  1. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. // 设置BeanFactory的类加载器、表达式解析器等
  3. beanFactory.setBeanClassLoader(getClassLoader());
  4. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  5. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  6. // 3.1 添加Aware执行器
  7. beanFactory.addBeanPostProcessor(new ApplicationContextDProcessor(this));
  8. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  9. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  10. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  11. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  12. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  13. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  14. // 3.2 自动注入的支持
  15. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  16. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  17. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  18. beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  19. // 3.3 添加监听器执行器
  20. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  21. // Detect a LoadTimeWeaver and prepare for weaving, if found.
  22. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  23. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  24. // Set a temporary ClassLoader for type matching.
  25. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  26. }
  27. // Register default environment beans.
  28. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
  29. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  30. }
  31. if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
  32. beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  33. }
  34. if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
  35. beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  36. }
  37. }

3.1 ApplicationContextDProcessor:Aware执行器

ApplicationContextDProcessor实现了BeanPostProcessor的postProcessBeforeInitialization接口,在所有Bean初始化前会执行当前方法

  1. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  2. //判断Bean是Aware的子类
  3. if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
  4. bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
  5. bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
  6. return bean;
  7. }
  8. AccessControlContext acc = null;
  9. if (System.getSecurityManager() != null) {
  10. acc = this.applicationContext.getBeanFactory().getAccessControlContext();
  11. }
  12. if (acc != null) {
  13. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  14. invokeAwareInterfaces(bean);
  15. return null;
  16. }, acc);
  17. }
  18. else {
  19. //回调执行Aware接口
  20. invokeAwareInterfaces(bean);
  21. }
  22. return bean;
  23. }

如果当前Bean是Aware的子类,那么将Bean强转成Aware类型,通过回调将信息设置到Bean中

  1. private void invokeAwareInterfaces(Object bean) {
  2. if (bean instanceof EnvironmentAware) {
  3. ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
  4. }
  5. if (bean instanceof EmbeddedValueResolverAware) {
  6. ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  7. }
  8. if (bean instanceof ResourceLoaderAware) {
  9. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  10. }
  11. if (bean instanceof ApplicationEventPublisherAware) {
  12. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  13. }
  14. if (bean instanceof MessageSourceAware) {
  15. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  16. }
  17. if (bean instanceof ApplicationContextAware) {
  18. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  19. }
  20. }

3.2 registerResolvableDependency:自动注入的支持

如果过容器中有多个相同接口的实现类,那么在自动注入的时候会注入注册的实现类

  1. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  2. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  3. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  4. beanFactory.registerResolvableDependency(ApplicationContext.class, this);

3.3 添加监听器执行器

ApplicationListenerDetector主要作用是添加和销毁监听器,实现了BeanPostProcessor的postProcessAfterInitialization(Bean实例化之后)方法和DestructionAwareBeanPostProcessor的postProcessBeforeDestruction(Bean销毁之前)方法

详情:https://www.jb51.net/article/277948.htm

四、BeanFactory的后置处理

这是个模压方法,由子类AnnotationConfigServletWebServerApplicationContext实现

  1. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. }

AnnotationConfigServletWebServerApplicationContext首先调了父类 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法

  1. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. //4.1后置处理Bean工厂
  3. super.postProcessBeanFactory(beanFactory);
  4. if (this.basePackages != null && this.basePackages.length > 0) {
  5. //basePackages为空不会执行
  6. this.scanner.scan(this.basePackages);
  7. }
  8. if (!this.annotatedClasses.isEmpty()) {
  9. this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
  10. }
  11. }

4.1 后置处理bean工厂

父类ServletWebServerApplicationContext首先向Bean工厂中注入了一个执行器

  1. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. //4.1.1注入执行器
  3. beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
  4. beanFactory.ignoreDependencyInterface(ServletContextAware.class);
  5. //4.1.2注册作用域
  6. registerWebApplicationScopes();
  7. }

4.1.1 WebApplicationContextServletContextAwareProcessor

WebApplicationContextServletContextAwareProcessor继承了ServletContextAwareProcessor

ServletContextAwareProcessor继承了BeanPostProcessor实现了postProcessBeforeInitialization(Bean初始化前执行)

  1. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  2. //注入ServletContext
  3. if (getServletContext() != null && bean instanceof ServletContextAware) {
  4. ((ServletContextAware) bean).setServletContext(getServletContext());
  5. }
  6. //注入ServletConfig
  7. if (getServletConfig() != null && bean instanceof ServletConfigAware) {
  8. ((ServletConfigAware) bean).setServletConfig(getServletConfig());
  9. }
  10. return bean;
  11. }

4.1.2 registerWebApplicationScopes 注册web的应用域

  1. // 所在类及方法:ServletWebServerApplicationContext#registerWebApplicationScopes
  2. private void registerWebApplicationScopes() {
  3. ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
  4. WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
  5. existingScopes.restore();
  6. }

ExistingWebApplicationScopes是ServletWebServerApplicationContext类中的一个静态类

源码如下:

  1. public static class ExistingWebApplicationScopes {
  2. static {
  3. Set<String> scopes = new LinkedHashSet<>();
  4. scopes.add(WebApplicationContext.SCOPE_REQUEST);
  5. scopes.add(WebApplicationContext.SCOPE_SESSION);
  6. SCOPES = Collections.unmodifiableSet(scopes);
  7. }
  8. // 这是构造方法,大概就是根据SCOPES获取beanFactory中已经注册的scope,然后放入scopes
  9. // 需要注意的是,在上面的方法中,第二行才在向beanFactory中注册,也就是这时的beanFactory里面没有request和session这两个scop
  10. // 所以这里就完成了beanFactory的赋值。建议打断点进去看看
  11. public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
  12. this.beanFactory = beanFactory;
  13. for (String scopeName : SCOPES) {
  14. Scope scope = beanFactory.getRegisteredScope(scopeName);
  15. if (scope != null) {
  16. this.scopes.put(scopeName, scope);
  17. }
  18. }
  19. }
  20. // 由于上面的方法并没有值存入scopes,所以这里也就没执行里面的内容
  21. public void restore() {
  22. this.scopes.forEach((key, value) -> {
  23. if (logger.isInfoEnabled()) {
  24. logger.info("Restoring user defined scope " + key);
  25. }
  26. this.beanFactory.registerScope(key, value);
  27. });
  28. }
  29. }

WebApplicationContextUtils.registerWebApplicationScopes(),这个方法就是向beanFactory注册web的scope了,源码如下

  1. public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
  2. registerWebApplicationScopes(beanFactory, null);
  3. }
  4. public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
  5. @Nullable ServletContext sc) {
  6. // 注册作用域
  7. beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// 注册request SCOP
  8. beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());// 注册session SCOP
  9. if (sc != null) {
  10. ServletContextScope appScope = new ServletContextScope(sc);
  11. beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // 注册application SCOP
  12. // Register as ServletContext attribute, for ContextCleanupListener to detect it.
  13. sc.setAttribute(ServletContextScope.class.getName(), appScope);
  14. }
  15. // 添加依赖项
  16. beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
  17. beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
  18. beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
  19. beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
  20. if (jsfPresent) {
  21. FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
  22. }
  23. }

以上就是Spring refresh()源码解析的详细内容,更多关于Spring refresh()的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号