Java面试专题 - 框架篇

参考视频:满神Java面试专题

笔记的整体结构依据视频编写,并随着学习的深入补充了很多知识

1. Spring refresh 流程

Spring refresh 概述

refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:

  1. prepareRefresh

  2. obtainFreshBeanFactory

  3. prepareBeanFactory

  4. postProcessBeanFactory

  5. invokeBeanFactoryPostProcessors

  6. registerBeanPostProcessors

  7. initMessageSource

  8. initApplicationEventMulticaster

  9. onRefresh

  10. registerListeners

  11. finishBeanFactoryInitialization

  12. finishRefresh

org.springframework.context.support.AbstractApplicationContext#refresh

java
    @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();
			}
		}
    }

功能分类

  • 1 为准备环境

  • 2 3 4 5 6 为准备 BeanFactory

    • ApplicationContext只是一个外部的容器,它的一些核心功能还得另外交给这个叫BeanFactory容器来完成,即Bean的创建,Bean的依赖注入,Bean的初始化,ApplicationContext会借助其成员变量BeanFactory来完成Bean的创建,Bean的依赖注入,Bean的初始化等功能
  • 7 8 9 10 12 为准备 ApplicationContext

  • 11 为初始化 BeanFactory 中非延迟单例 bean

1. prepareRefresh

  • 这一步创建和准备了 Environment 对象,它作为 ApplicationContext 的一个成员变量

  • Environment 对象的作用之一是为后续 @Value,值注入时提供键值

  • Environment 分成三个主要部分

    • systemProperties - 保存 java 环境键值
    • systemEnvironment - 保存系统环境键值(操作系统的键值,如JAVA_HOME、PATH、CLASS_PATH等)
    • 自定义 PropertySource - 保存自定义键值,例如来自于 *.properties 文件的键值
image-20210902181639048
  • 解析@Value、${}、#{}
image-20230421212541621
java
    /**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     * 准备此上下文以进行刷新、设置其启动日期和活动标志以及执行属性源的任何初始化。
     */
    protected void prepareRefresh() {
       ...

       // Initialize any placeholder property sources in the context environment.
       initPropertySources();

       // Validate that all properties marked as required are resolvable:
       // see ConfigurablePropertyResolver#setRequiredProperties
       getEnvironment().validateRequiredProperties();

       ...
    }

2. obtainFreshBeanFactory

  • 这一步获取(或创建) BeanFactory,它也是作为 ApplicationContext 的一个成员变量
  • ApplicationContext+BeanFactory:ApplicationContext在Bean的管理上借助BeanFactory的功能
  • BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化,bean 的各项特征由 BeanDefinition 定义
    • BeanDefinition 作为 bean 的设计蓝图,规定了 bean 的特征,如单例多例、依赖关系、初始销毁方法等
    • BeanDefinition 的来源有多种多样,可以是通过 xml 获得、配置类获得、组件扫描获得,也可以是编程添加
  • 所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合;
image-20210902182004819
image-20230421223009256
  • BeanFactory中也有很多成员变量要初始化,其中有一个非常重要的beanDefinitionMap,BeanFactory并不是一上来就创建这些Bean,它必须先有些Bean的定义,它得知道这个Bean长什么样子,Bean是单例还是多例,它的初始化方法是什么,它有哪些属性需要依赖注入,这些信息在Spring中都是用beanDefinitionMap这个类来描述的,而这个beanDefinitionMap是用来存储所有的BeanDefinition
  • BeanFactory不是一下子就把Bean创建出来,得借助BeanDefinition(Bean的设计蓝图),刚开始都是收集BeanDefinition的各种信息
  • 此方法仅在AbstractApplicationContext类内被调用且未被重写
java
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
       refreshBeanFactory();
       return getBeanFactory();
    }
  • 以下两个方法由AbstractRefreshableApplicationContext和GenericApplicationContext两个类重写,且创建或获取的BeanFactory类型都为DefaultListableBeanFactory
java

    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;



	@Override
	public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

3. prepareBeanFactory

java
/**
 * Configure the factory's standard context characteristics,
 * such as the context's ClassLoader and post-processors.
 * @param beanFactory the BeanFactory to configure
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   ......
}
  • 这一步会进一步完善 BeanFactory,为它的各项成员变量赋值
  • beanExpressionResolver 用来解析 SpEL,常见实现为 StandardBeanExpressionResolver
java
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  • propertyEditorRegistrar 会注册类型转换器

    • 它在这里使用了 ResourceEditorRegistrar 实现类
    • 并应用 ApplicationContext 提供的 Environment 完成 ${ } 解析
    java
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  • registerResolvableDependency 来注册 beanFactory 以及 ApplicationContext,让它们也能用于依赖注入

java
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  • beanPostProcessors 是 bean 后处理器集合,会工作在 bean 的生命周期各个阶段,此处会添加两个:

    • ApplicationContextAwareProcessor 用来解析 Aware 接口
    java
    // Configure the bean factory with context callbacks.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    • ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean
    java
    // Register early post-processor for detecting inner beans as ApplicationListeners.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    • 粉红正方形代表内置的Bean后处理器
image-20210902182541925
  • beanExpressionResolver是用来解析SpringEL表达式(SpEL),即#{}
  • propertyEditorRegistrar是注册一些类型转换器,因为Spring接下来尤其是做值注入,需要把字符串类型转换为一些其他类型,此时需要注册一些propertyEditor转换器来完成转换
  • resolvableDependencies是管理一些特殊的对象用来进行依赖注入,因为将来大部分的Bean都是放在singletonObjects单例Bean工厂里去完成依赖注入,但是有些比较特殊的对象,如注入BeanFactory本身或者注入ApplicationContext本身,这些对象不是真正的Bean(特殊对象而已,还算不上Bean),它们没有在这个单例池里,没有在这个BeanDefinition里去定义,那么查询这些特殊Bean就是在这个resolvableDependencies里查
  • beanPostProcessors是在我们Bean创建时,对这个Bean的各项功能做一些扩展,对里面的一些注解进行识别,Spring标准的功能里功能是非常有限的,它对Bean的创建过程做各种各样的扩展时必须借助于很多的beanPostProcessor

4. postProcessBeanFactory

  • 这一步是空实现,留给子类扩展。(Bean工厂的一种扩展方式)

    java
    /**
     * 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
     */
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }
    • 一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope,完善 Web 下的 BeanFactory
  • 这里体现的是模板方法设计模式

ApplicationContext将来可能有不同的子类,有一种是非web环境下的子类,还有一种是web环境下的子类,那web环境下的子类初始化beanFactory,就需要更多的信息,比如要注册一些新的scope,非web环境下的子类,只需要有singleton和prototype这两种scope,web环境下可能还需要request,session这样的scope,所以该方法就没有实现,留给子类扩展


5. invokeBeanFactoryPostProcessors

java
/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before singleton instantiation.
 * 实例化并调用所有已注册的 BeanFactoryPostProcessor bean,如果给定则遵循显式顺序。必须在单例化之前调用。
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}
  • 这一步会调用 beanFactory 后处理器(Bean工厂的另一种扩展方式)

    • 实际上将来真正工作的时候不可能为了扩展功能就去实现新的ApplicationContext子类,所以更好的扩展方式就是通过Bean工厂后处理器的方式来扩展BeanFactory的功能
  • beanFactory 后处理器充当 beanFactory 的扩展点,可以用来补充或修改 BeanDefinition

java
public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    ...
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {    
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        ...
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
    ...
    }
}
  • 常见的 beanFactory 后处理器有

    • ConfigurationClassPostProcessor – 解析 @Configuration、@Bean、@Import、@PropertySource 等
    java
    public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
          PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {...}
    • PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${}(XML的ApplicationContext实现用的多)
    • MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition
image-20230421232304434

beanFactory 后处理器在refresh方法调用之前就有一部分后处理器加入到容器了

java
public ConfigurableApplicationContext run(String... args) {
    ...
	prepareContext(context, environment, listeners, applicationArguments, printedBanner);
	refreshContext(context);
	afterRefresh(context, applicationArguments);    
    ...

}

6. registerBeanPostProcessors

java
/**
 * Instantiate and register all BeanPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before any instantiation of application beans.
 * 实例化并注册所有 BeanPostProcessor bean,如果给定则遵守显式顺序。必须在任何应用程序 bean 实例化之前调用。
 */
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
  • 这一步是继续从 beanFactory 中找出 bean 后处理器,添加至 beanPostProcessors 集合中
java
public static void registerBeanPostProcessors(
      ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

   String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

   // Register BeanPostProcessorChecker that logs an info message when
   // a bean is created during BeanPostProcessor instantiation, i.e. when
   // a bean is not eligible for getting processed by all BeanPostProcessors.
   int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
   beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

   // Separate between BeanPostProcessors that implement PriorityOrdered,
   // Ordered, and the rest.
   List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   for (String ppName : postProcessorNames) {
      if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
         BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
         priorityOrderedPostProcessors.add(pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
         }
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }

   // First, register the BeanPostProcessors that implement PriorityOrdered.
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

   // Next, register the BeanPostProcessors that implement Ordered.
   List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String ppName : orderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      orderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, orderedPostProcessors);

   // Now, register all regular BeanPostProcessors.
   List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String ppName : nonOrderedPostProcessorNames) {
      BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
      nonOrderedPostProcessors.add(pp);
      if (pp instanceof MergedBeanDefinitionPostProcessor) {
         internalPostProcessors.add(pp);
      }
   }
   registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

   // Finally, re-register all internal BeanPostProcessors.
   sortPostProcessors(internalPostProcessors, beanFactory);
   registerBeanPostProcessors(beanFactory, internalPostProcessors);

   // Re-register post-processor for detecting inner beans as ApplicationListeners,
   // moving it to the end of the processor chain (for picking up proxies etc).
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
  • bean 后处理器充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段,常见的有:

    • AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value
    image-20231128221603715
    • CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy
    image-20231128222113889
    • AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理
    image-20231128221128903
image-20230421232557342
image-20230421232957513

Bean的后处理器是对我们Bean创建的过程中做各种功能的增强,而Bean的后处理器其实都是从beanDefinitionMap中去搜索,看看里面这些BeanDefinition有没有实现BeanPostProcessor接口,如果实现了接口就会识别出来是个特殊的Bean,是个Bean的后处理器,那么就会把这样的Bean创建出来,创建出来以后,把这个Bean的后处理器对象加人到这个beanPostProcessors集合里,那在Ben真正创建的时候就会用到这些后处理器


7. initMessageSource

  • 这一步是为 ApplicationContext 添加 messageSource 成员,实现国际化功能
  • 去 beanFactory 内找名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现
java
/**
 * Initialize the MessageSource.
 * Use parent's if none defined in this context.
 */
protected void initMessageSource() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
      // Make MessageSource aware of parent MessageSource.
      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
         if (hms.getParentMessageSource() == null) {
            // Only set parent context as parent MessageSource if no parent MessageSource
            // registered already.
            hms.setParentMessageSource(getInternalParentMessageSource());
         }
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Using MessageSource [" + this.messageSource + "]");
      }
   }
   else {
      // Use empty MessageSource to be able to accept getMessage calls.
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
      }
   }
}
image-20210902183819984

8. initApplicationContextEventMulticaster

  • 这一步为 ApplicationContext 添加事件广播器成员,即 applicationContextEventMulticaster
  • 它的作用是发布事件给监听器
  • 去 beanFactory 找名为 applicationEventMulticaster 的 bean 作为事件广播器,若没有,会创建默认的事件广播器
  • 之后就可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件
java
/**
 * Initialize the ApplicationEventMulticaster.
 * Uses SimpleApplicationEventMulticaster if none defined in the context.
 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
 */
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
               "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
      }
   }
}
image-20210902183943469

9. onRefresh

java
/**
 * Template method which can be overridden to add context-specific refresh work.
 * Called on initialization of special beans, before instantiation of singletons.
 * <p>This implementation is empty.
 * @throws BeansException in case of errors
 * @see #refresh()
 */
protected void onRefresh() throws BeansException {
   // For subclasses: do nothing by default.
}
  • 这一步是空实现,留给子类扩展
    • SpringBoot 中的子类在这里准备了 WebServer,即内嵌 web 容器
  • 体现的是模板方法设计模式

10. registerListeners

  • 这一步会从多种途径找到事件监听器,并添加至 applicationEventMulticaster
  • 事件监听器顾名思义,用来接收事件广播器发布的事件,有如下来源
    • 事先编程添加的
    • 来自容器中的 bean
    • 来自于 @EventListener 的解析
  • 要实现事件监听器,只需要实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可
java
/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}
  • 微系统与第三方框架licationEventMulticaster 的实现类执行所有监听器的 onApplicationEvent 方法
java
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	......

	@SuppressWarnings({"rawtypes", "unchecked"})
	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.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

	......

}
image-20210902184343872

11. finishBeanFactoryInitialization

  • 这一步会将 beanFactory 的成员补充完毕,并初始化所有非延迟单例 bean
  • conversionService 也是一套转换机制,作为对 PropertyEditor 的补充
  • embeddedValueResolvers 即内嵌值解析器,用来解析 @Value 中的 ${},借用的是 Environment 的功能
  • singletonObjects 即单例池,缓存所有单例对象
    • 对象的创建都分三个阶段,每一阶段都有不同的 bean 后处理器参与进来,扩展功能
java
/**
 * Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();
}
image-20210902184641623
  • conversionService 也是做类型转换的,由于 Spring 的历史原因,最早是 propertyEditorRegistrars 来转换的,后来发现功能上、实现上有些欠考虑,因此设计了 conversionService 接口,这两个转换器是并存的
  • embeddedValueResolvers 是做 ${} 这种内嵌值的解析,间接地调用 Environment 的功能来完成 ${} 的解析,只不过是从属于 BeanFactory 中的成员
  • singletonObjects (单例池,用来缓存所有单例对象)是单例对象集合,它会找到 beanDefinitionMap 中所有使用到单例的对象,看有没有初始化方法,有没有依赖注入信息等,根据这些来创建Bean,前提是非延迟单例对象,如果是非延迟单例对象,这一步它就会把 Bean 的实例对象创建出来,如果是延迟单例对象,你第一次用到它的时候才会创建,在创建的过程中,之前的 beanPostProcessors 都可以派上用场,它们会工作在 Bean 创建的各个阶段,分为三个大的阶段,Bean 的创建、Bean 的依赖注入、Bean 的初始化,每个阶段都有不同的 Bean 后处理器参与进来,扩展功能

12. finishRefresh

  • 这一步会为 ApplicationContext 添加 lifecycleProcessor 成员,用来控制容器内需要生命周期管理的 bean
  • 如果容器中有名称为 lifecycleProcessor 的 bean 就用它,否则创建默认的生命周期管理器
  • 准备好生命周期管理器,就可以实现
    • 调用 context 的 start,即可触发所有实现 LifeCycle 接口 bean 的 start
    • 调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop
  • 发布 ContextRefreshed 事件,整个 refresh 执行完成
java
/**
 * Finish the refresh of this context, invoking the LifecycleProcessor's
 * onRefresh() method and publishing the
 * {@link org.springframework.context.event.ContextRefreshedEvent}.
 */
protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();

   // Initialize lifecycle processor for this context.
   initLifecycleProcessor();

   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();

   // Publish the final event.
   publishEvent(new ContextRefreshedEvent(this));

   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}
image-20210902185052433

lifecycleProcessor (生命周期处理器): 整个 Spring 容器中有很多的 Bean,它们都有自己独立的生命周期,都有一个停止,启动之类的生命周期处理,这里的生命周期并不是指初始化销毁,可以理解为一种服务,可以停止和启动,同样的从 beanDefinitionMap 中找到一个 lifecycleProcessor 的 Bean,如果有就直接用,没有它就用自己默认的生命周期处理器,这个 lifecycleProcessor 里面有 start 方法,可以调用 Bean 工厂中其他实现 lifecycleProcessor 接口的Bean的 start 方法,调用 stop 方法也一样,起到一个总控的作用,这个生命周期处理器创建好以后可以发布 ContextRefreshed 事件,表示整个 Spring 容器已经初始化( Refresh )完成


总结

image-20230422003035699

2. Spring bean 生命周期

bean 生命周期 概述

image-20230422003651658
  • 里面的这些Bean符合懒惰式初始化,开始并不会创建这些Bean,当你第一次获取时,才会创建这些Bean的实例,然后进行依赖注入初始化等操作,以doGetBean作为起点

bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可以总结为以下七个阶段:

  1. 处理名称,检查缓存
  2. 处理父子容器
  3. 处理 dependsOn
  4. 选择 scope 策略
  5. 创建 bean
  6. 类型转换处理
  7. 销毁 bean

注意

  • 划分的阶段和名称并不重要,重要的是理解整个过程中做了哪些事情

1. 处理名称,检查缓存

  • 这一步会处理别名,将别名解析为实际名称
  • 对 FactoryBean 也会特殊处理,如果以 & 开头表示要获取 FactoryBean 本身,否则表示要获取其产品
  • 这里针对单例对象会检查一级、二级、三级缓存
    • singletonFactories 三级缓存,存放单例工厂对象
    • earlySingletonObjects 二级缓存,存放单例工厂的产品对象
      • 如果发生循环依赖,产品是代理;无循环依赖,产品是原始对象
    • singletonObjects 一级缓存,存放单例成品对象
java
//org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
{
    ...
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
       if (logger.isTraceEnabled()) {
          if (isSingletonCurrentlyInCreation(beanName)) {
             logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                   "' that is not fully initialized yet - a consequence of a circular reference");
          }
          else {
             logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
          }
       }
       bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
	...
}
image-20230422005021610

2. 处理父子容器

  • 如果当前容器根据名字找不到这个 bean,此时若父容器存在,则执行父容器的 getBean 流程
  • 优先找子容器的 bean,找到了直接返回,找不到继续到父容器找
  • 父子容器的 bean 名称可以重复
java
//org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
{
    ...
    // Check if bean definition exists in this factory.
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
       // Not found -> check parent.
       String nameToLookup = originalBeanName(name);
       if (parentBeanFactory instanceof AbstractBeanFactory) {
          return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                nameToLookup, requiredType, args, typeCheckOnly);
       }
       else if (args != null) {
          // Delegation to parent with explicit args.
          return (T) parentBeanFactory.getBean(nameToLookup, args);
       }
       else if (requiredType != null) {
          // No args -> delegate to standard getBean method.
          return parentBeanFactory.getBean(nameToLookup, requiredType);
       }
       else {
          return (T) parentBeanFactory.getBean(nameToLookup);
       }
    }
    ...
}

首先查找缓存,缓存里有就直接返回,缓存里如果没有,也不会立刻去创建这个Bean,如果容器中又配置了父容器的话,缓存里没有它会到父容器里查找,看看里面有没有创建好的Bean,如果有就用父容器的Bean,就不用走创建流程,如果还没有才走后续流程


3. 处理 dependsOn

  • 如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean,这一步会提前创建这些 dependsOn 的 bean
  • 所谓非显式依赖,就是指两个 bean 之间不存在直接依赖关系,但需要控制它们的创建先后顺序
java
//org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
{
    ...
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);

    // Guarantee initialization of beans that the current bean depends on.
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
       for (String dep : dependsOn) {
          if (isDependent(beanName, dep)) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                   "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
          }
          registerDependentBean(dep, beanName);
          try {
             getBean(dep);
          }
          catch (NoSuchBeanDefinitionException ex) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                   "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
          }
       }
    }
    ...
}
image-20230422005341839

大部分的Bean都有依赖关系,这些有依赖关系的Bean它们创建的次序是可以保障的,那些没有依赖关系的Bean可以使用dependsOn来控制次序


4. 选择 scope 策略

  • 对于 singleton scope,首先到单例池去获取 bean,如果有则直接返回,没有再进入创建流程
  • 对于 prototype scope,每次都会进入创建流程
  • 对于自定义 scope,例如 request,首先到 request 域获取 bean,如果有则直接返回,如果没有,则创建并放入 request
java
//org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
{
    ...
    // Create bean instance.
       if (mbd.isSingleton()) {
          sharedInstance = getSingleton(beanName, () -> {
             try {
                return createBean(beanName, mbd, args);
             }
             catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
             }
          });
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
       }

       else if (mbd.isPrototype()) {
          // It's a prototype -> create a new instance.
          Object prototypeInstance = null;
          try {
             beforePrototypeCreation(beanName);
             prototypeInstance = createBean(beanName, mbd, args);
          }
          finally {
             afterPrototypeCreation(beanName);
          }
          bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
       }

       else {
          String scopeName = mbd.getScope();
          final Scope scope = this.scopes.get(scopeName);
          if (scope == null) {
             throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
          }
          try {
             Object scopedInstance = scope.get(beanName, () -> {
                beforePrototypeCreation(beanName);
                try {
                   return createBean(beanName, mbd, args);
                }
                finally {
                   afterPrototypeCreation(beanName);
                }
             });
             bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
          }
          catch (IllegalStateException ex) {
             throw new BeanCreationException(beanName,
                   "Scope '" + scopeName + "' is not active for the current thread; consider " +
                   "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                   ex);
          }
       }
    }
    ...
}
image-20230422011157499

5 创建 bean

image-20230422013329269
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
	...
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	...
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	...
}

5.1 创建 bean - 创建 bean 实例

要点总结
有自定义 TargetSource 的情况由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回
Supplier 方式创建 bean 实例为 Spring 5.0 新增功能,方便编程方式创建 bean 实例
FactoryMethod 方式 创建 bean 实例① 分成静态工厂与实例工厂;② 工厂方法若有参数,需要对工厂方法参数进行解析,利用 resolveDependency;③ 如果有多个工厂方法候选者,还要进一步按权重筛选
AutowiredAnnotationBeanPostProcessor① 优先选择带 @Autowired 注解的构造;② 若有唯一的带参构造,也会入选
mbd.getPreferredConstructors选择所有公共构造,这些构造之间按权重筛选
采用默认构造如果上面的后处理器和 BeanDefinition 都没找到构造,采用默认构造,即使是私有的 ( 私有构造方法也会用私有的构造创建 Bean 的实例,使用暴力反射并通过私有构造方法进行方法调用 )
  • 创建 bean 实例之前,有自定义 TargetSource 的情况
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   	...
 	bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
	...
	bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
	...
}

@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   ...
         Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
   ...
}

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
	throws BeansException {
 	...
	Object current = processor.postProcessAfterInitialization(result, beanName);
	...
}
java
	//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
	//创建 bean 实例之前
	@Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
       Object cacheKey = getCacheKey(beanClass, beanName);

       if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
          if (this.advisedBeans.containsKey(cacheKey)) {
             return null;
          }
          if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
             this.advisedBeans.put(cacheKey, Boolean.FALSE);
             return null;
          }
       }

       // Create proxy here if we have a custom TargetSource.
       // Suppresses unnecessary default instantiation of the target bean:
       // The TargetSource will handle target instances in a custom fashion.
       TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
       if (targetSource != null) {
          if (StringUtils.hasLength(beanName)) {
             this.targetSourcedBeans.add(beanName);
          }
          Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
          Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
          this.proxyTypes.put(cacheKey, proxy.getClass());
          return proxy;
       }

       return null;
    }
	//bean 初始化完成之后
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
  • 默认情况
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
    ...
}
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   ...

   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         return instantiateBean(beanName, mbd);
      }
   }

   // Candidate constructors for autowiring?
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   ctors = mbd.getPreferredConstructors();
   if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   return instantiateBean(beanName, mbd);
}

5.2 创建 bean - 依赖注入

image-20230422013843155
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
{
        ...
        // Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}
    	// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
             //添加单例工厂
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
    	...
        	populateBean(beanName, mbd, instanceWrapper);
 	...
}
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}
  • AutowiredAnnotationBeanPostProcessor
java
//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}
  • CommonAnnotationBeanPostProcessor
java
//org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
   InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}
  • AUTOWIRE_BY_NAME;AUTOWIRE_BY_TYPE;resolveDependency;applyPropertyValues
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   ...

   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      ...
   }

   ...
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}
要点总结
AutowiredAnnotationBeanPostProcessor识别 @Autowired 及 @Value 标注的成员,封装为 InjectionMetadata 进行依赖注入
CommonAnnotationBeanPostProcessor识别 @Resource 标注的成员,封装为 InjectionMetadata 进行依赖注入
resolveDependency用来查找要装配的值,可以识别:① Optional;② ObjectFactory 及 ObjectProvider;③ @Lazy 注解;④ @Value 注解(${}, #{}, 类型转换);⑤ 集合类型(Collection,Map,数组等);⑥ 泛型和 @Qualifier(用来区分类型歧义);⑦ primary 及名字匹配(用来区分类型歧义)
AUTOWIRE_BY_NAME根据成员名字找 bean 对象,修改 mbd 的 propertyValues,不会考虑简单类型的成员
AUTOWIRE_BY_TYPE根据成员类型执行 resolveDependency 找到依赖注入的值,修改 mbd 的 propertyValues
applyPropertyValues根据 mbd 的 propertyValues 进行依赖注入(即xml中 `<property name ref
  • 相同成员依赖注入优先级:精准匹配>按类型/名字匹配>注解方式匹配
image-20230422014541831

Bean的实例对象刚刚创建时里面是空空如也的,需要不断补充和完善它,接下来就对当前这个Bean的实例进行依赖注入,即建立当前这个Bean的实例跟容器中其他Bean之间的依赖关系,可以通过注解匹配和根据类型以及名字匹配

  • 在依赖注入阶段,有个条件是产生循环依赖,产生循环依赖以后,它会在单例工厂池中通过一个工厂对象来间接的调用到我们的自动代理后处理器类来创建代理
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference
      ...
         exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
      ...
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference         
	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
         //创建代理方法
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

5.3 创建 bean - 初始化

image-20230422014943738
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
{    
    ...
    // Initialize the bean instance.
    Object exposedObject = bean;
    ...
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    ...

}
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   ...
      invokeInitMethods(beanName, wrappedBean, mbd);
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      //有自定义 TargetSource 的情况由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}
要点总结
内置 Aware 接口的装配包括 BeanNameAware,BeanFactoryAware 等
扩展 Aware 接口的装配由 ApplicationContextAwareProcessor 解析,执行时机在 postProcessBeforeInitialization
@PostConstruct由 CommonAnnotationBeanPostProcessor 解析,执行时机在 postProcessBeforeInitialization
InitializingBean通过接口回调执行初始化
initMethod根据 BeanDefinition 得到的初始化方法执行初始化,即 <bean init-method> 或 @Bean(initMethod)
创建 aop 代理由 AnnotationAwareAspectJAutoProxyCreator 创建,执行时机在 postProcessAfterInitialization
  • 初始化顺序:
    • 1.执行BeanFactoryAware接口的定义的初始化方法setBeanFactory
    • 2.执行标注@PostConstruct的方法init
    • 3.执行InitializingBean接口的重写方法初始化afterPorpertiesSet
    • 4.执行用BeanDefinition指定的初始化方法
image-20230422015021268

初始化阶段:处理一些Aware接口、调用初始化方法、创建aop代理(如果你的Bean跟切面表达式匹配上,就帮你创建代理),在初始化阶段,由Spring的BeanFactory容器来回调Aware接口中的方法,如你实现了BeanFactoryAware接口,就会相应地把BeanFactory对象通过回调此接口的方法给你传递进来 初始化方法:@PostConstruct是通过一个Bean的后处理器来进行调用的


5.4 创建 bean - 注册可销毁 bean

image-20230422015302186
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
...
// Register bean as disposable.
try {
   registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
   throw new BeanCreationException(
         mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
...
java
//org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
   AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
   if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
      if (mbd.isSingleton()) {
         // Register a DisposableBean implementation that performs all destruction
         // work for the given bean: DestructionAwareBeanPostProcessors,
         // DisposableBean interface, custom destroy method.
         registerDisposableBean(beanName,
               new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
      }
      else {
         // A bean with a custom scope...
         Scope scope = this.scopes.get(mbd.getScope());
         if (scope == null) {
            throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
         }
         scope.registerDestructionCallback(beanName,
               new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
      }
   }
}

在这一步判断并登记可销毁 bean

  • 判断依据
    • 如果实现了 DisposableBean 或 AutoCloseable 接口,则为可销毁 bean
    • 如果自定义了 destroyMethod,则为可销毁 bean
    • 如果采用 @Bean 没有指定 destroyMethod,则采用自动推断方式获取销毁方法名(close,shutdown)
    • 如果有 @PreDestroy 标注的方法
  • 存储位置
    • singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中
    • 自定义 scope 的可销毁 bean 会存储于对应的域对象当中
    • prototype scope 不会存储,需要自己找到此对象销毁
  • 存储时都会封装为 DisposableBeanAdapter 类型对销毁方法的调用进行适配

6. 类型转换处理

  • 如果 getBean 的 requiredType 参数与实际得到的对象类型不同,会尝试进行类型转换
  • 这时Bean已经被创建并作为结果返回
image-20230422015511898

7. 销毁 bean

  • 销毁时机
    • singleton bean 的销毁在 ApplicationContext.close 时,此时会找到所有 DisposableBean 的名字,逐一销毁
    • 自定义 scope bean 的销毁在作用域对象生命周期结束时(这类Bean的销毁时机在request域生命周期结束的时候,在它结束之前调用request scope bean的一个销毁)
    • prototype bean 的销毁可以通过自己手动调用 AutowireCapableBeanFactory.destroyBean 方法执行销毁
  • 同一 bean 中不同形式销毁方法的调用次序
    • 优先后处理器销毁,即 @PreDestroy
    • 其次 DisposableBean 接口销毁
    • 最后 destroyMethod 销毁(包括自定义名称,推断名称,AutoCloseable 接口 多选一)

总结

image-20230422015825420

3. Spring bean 循环依赖

补充:创建代理

要点

  • 要完全理解循环依赖,需要理解代理对象的创建时机
  • 掌握 ProxyFactory 创建代理的过程,理解 Advisor,Advice,Pointcut 与 Aspect
  • 掌握 AnnotationAwareAspectJAutoProxyCreator 筛选 Advisor 合格者,创建代理的过程
    • bean 的后处理器,作用是为我们容器中的 bean,那些目标 bean 需不需要为之创建代理,它内部也会间接调用 ProxyFactory 来创建代理

代理工厂

  • 只加了通知(环绕通知)来进行功能增强
image-20230423122730735
image-20231202153033525
  • 加入切点,观察CGLIB动态代理和JDK动态代理的区别
image-20230423123833981

说说 JDK 动态代理和 CGLIB 代理 ?

Spring 的 AOP 是通过动态代理open in new window来实现的,动态代理主要有两种方式 JDK 动态代理和 Cglib 动态代理,这两种动态代理的使用和原理有些不同。

JDK 动态代理

  1. Interface:对于 JDK 动态代理,目标类需要实现一个 Interface。
  2. InvocationHandler:InvocationHandler 是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,在此过程,可能包装逻辑,对目标方法进行前置后置处理。
  3. Proxy:Proxy 利用 InvocationHandler 动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象。

CgLib 动态代理

  1. 使用 JDK 创建代理有一大限制,它只能为接口创建代理实例,而 CgLib 动态代理就没有这个限制。
  2. CgLib 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
  3. CgLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 是采用动态创建子类的方法,对于 final 方法,无法进行代理。

我们来看一个常见的小场景,客服中转,解决用户问题:

用户向客服提问题

JDK 动态代理实现:

JDK动态代理类图
  • 接口

    java
    public interface ISolver {
        void solve();
    }
  • 目标类:需要实现对应接口

    java
    public class Solver implements ISolver {
        @Override
        public void solve() {
            System.out.println("疯狂掉头发解决问题……");
        }
    }
  • 态代理工厂:ProxyFactory,直接用反射方式生成一个目标对象的代理对象,这里用了一个匿名内部类方式重写 InvocationHandler 方法,实现接口重写也差不多

    java
    public class ProxyFactory {
    
        // 维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        // 为目标对象生成代理对象
        public Object getProxyInstance() {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("请问有什么可以帮到您?");
    
                            // 调用目标对象方法
                            Object returnValue = method.invoke(target, args);
    
                            System.out.println("问题已经解决啦!");
                            return null;
                        }
                    });
        }
    }
  • 客户端:Client,生成一个代理对象实例,通过代理对象调用目标对象方法

    java
    public class Client {
        public static void main(String[] args) {
            //目标对象:程序员
            ISolver developer = new Solver();
            //代理:客服小姐姐
            ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();
            //目标方法:解决问题
            csProxy.solve();
        }
    }

Cglib 动态代理实现:

Cglib动态代理类图
  • 目标类:Solver,这里目标类不用再实现接口。

    java
    public class Solver {
    
        public void solve() {
            System.out.println("疯狂掉头发解决问题……");
        }
    }
  • 动态代理工厂:

    java
    public class ProxyFactory implements MethodInterceptor {
    
       //维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        //为目标对象生成代理对象
        public Object getProxyInstance() {
            //工具类
            Enhancer en = new Enhancer();
            //设置父类
            en.setSuperclass(target.getClass());
            //设置回调函数
            en.setCallback(this);
            //创建子类对象代理
            return en.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("请问有什么可以帮到您?");
            // 执行目标对象的方法
            Object returnValue = method.invoke(target, args);
            System.out.println("问题已经解决啦!");
            return null;
        }
    
    }
  • 客户端:Client

    java
    public class Client {
        public static void main(String[] args) {
            //目标对象:程序员
            Solver developer = new Solver();
            //代理:客服小姐姐
            Solver csProxy = (Solver) new ProxyFactory(developer).getProxyInstance();
            //目标方法:解决问题
            csProxy.solve();
        }
    }

代理对象与advisor的关系

  • 代理对象会间接去引用这些Advisor切面
image-20230423124430187

@Aspect与advisor的关系

  • 注解方式,整个类是一个切面,方法是通知,注解里的表达式是切点,这些注解的方式最终还是会转换成MethodInterceptor和Advisor这种方式的,而且转换的方式是以这种通知方法为单位来进行转换的,如有一个Aspect1的类它里面有一个环绕通知,最终会转换成一个advisor的切面,一个通知方法对应一个advisor切面,一个类中有多个通知方法就分别对应一个advisor切面,advisor切面相当于是一种更基本的或是Spring内置的这种切面形式,对于这些环绕通知,前置通知,后置通知也好,它们最终都会转换成Spring内置的MethodInterceptor的这种环绕通知的调用方式
image-20230423143827599

AnnotationAwareAspectJAutoProxyCreator 自动代理后处理器

image-20231202162832299
  • wrapIfNecessary
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
...
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//↓↓
...
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
...
    return wrapIfNecessary(bean, beanName, cacheKey);//↓↓
...
//AbstractAutoProxyCreator#wrapIfNecessary  
    // Create proxy if we have advice.
    ...
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    ...
//AbstractAutoProxyCreator#createProxy
...
	return proxyFactory.getProxy(classLoader);
...
image-20230423144839058
  • wrapIfNecessary-DEBUG
image-20230423150240536
  • 代理创建时机

    • 创建 bean 实例之前,如果你的bean自定义了 TargetSource,就会调用到自动代理后处理器来创建代理对象(用得较少,了解即可);
    • 在初始化阶段,会调用到这个自动代理后处理器,在初始化执行完以后,就要调用后处理器的 PostProcessAfterInitialization 方法,这时候就会用到这个自动代理后处理器来创建代理对象;
    • 在依赖注入阶段,有个条件是产生循环依赖,产生循环依赖以后,它会在单例工厂池中通过一个工厂对象来间接的调用到我们的自动代理后处理器类来创建代理
      • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean
    java
    /**
     * Applies the {@code postProcessAfterInitialization} callback of all
     * registered BeanPostProcessors, giving them a chance to post-process the
     * object obtained from FactoryBeans (for example, to auto-proxy them).
     * @see #applyBeanPostProcessorsAfterInitialization
     */
    @Override
    protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
       return applyBeanPostProcessorsAfterInitialization(object, beanName);
    }
image-20230423150540283
image-20230423150918284

总结

  • 最基本的切面是 Advisor,一个Aspect 切面对应一到多个 Advisor
  • 最基本的 Advice 是 Methodinterceptor,其它 Advice 最终都将适配为 Methodinterceptor
  • 创建代理的方式
    • 实现了用户自定义接口,采用jdk 动态代理
    • 没有实现用户自定义接口,采用 cglib 代理
    • 设置了 setProxyTargetClass(true),统一采用 cglib 代理
  • 切面、切点、通知等不会被代理
  • AnnotationAwareAspectJAutoProxyCreator 调用时机: 创建阶段、依赖注入阶段、初始化阶段

循环依赖的产生

  • 首先要明白,bean 的创建要遵循一定的步骤,必须是创建、注入、初始化三步,这些顺序不能乱
image-20210903085238916
  • set 方法(包括成员变量)的循环依赖如图所示

    • 可以在【a 创建】和【a set 注入 b】之间加入 b 的整个流程来解决

    • 【b set 注入 a】 时可以成功,因为之前 a 的实例(未初始化)已经创建完毕

    • a 的顺序,及 b 的顺序都能得到保障

image-20210903085454603
  • 构造方法的循环依赖如图所示,显然无法用前面的方法解决
image-20230423164711640

构造循环依赖的解决

  • 思路1
    • a 注入 b 的代理对象,这样能够保证 a 的流程走通
    • 后续需要用到 b 的真实对象时,可以通过代理间接访问
image-20210903091627659
  • 思路2
    • a 注入 b 的工厂对象,让 b 的实例创建被推迟,这样能够保证 a 的流程先走通
    • 后续需要用到 b 的真实对象时,再通过 ObjectFactory 工厂间接访问
image-20210903091743366
image-20230423164819587
  • 示例1:用 @Lazy 为构造方法参数生成代理
image-20230423165237989

@Lazy 可以加在成员变量上或方法参数上,也包括构造方法的参数上,加了之后 Spring 就去查找依赖注入的值时,就根据此注解进行解析,查找依赖注入的值会调用到 beanFactory 中的一个 resolveDependency 的方法判断是否该值加了 @Lazy 注解,加了就会进行代理对象的创建,否则返回原始对象

  • 示例2:用 ObjectFactory 或 ObjectProvider 延迟依赖对象的创建
image-20230423165816753

ObjectFactory 和 ObjectProvider 都是 Spring 提供的工厂接口

  • 示例3:用 @Scope 产生代理
image-20230423170840218

在 @Lazy 和 @Scope 这两种代理中选择创建代理的话,会选择 @Lazy,因为 @Scope 是一种比较 low 的解决方式,因为它是由代理工厂来生产代理对象的,所以这里就绕了一个弯,而且真正的目标也会在我们的单例池里存一份(scopeTarget.b)

  • 示例4:用 Provider 接口解决,原理上与 ObjectProvider 一样,Provider 接口是独立的 jar 包,需要加入依赖
xml
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
image-20230423170300385

Provider这个接口是java官方提供的一套工厂接口,在pom文件加入javax.inject的依赖,它的作用跟前面的两个工厂接口的作用是一样的,即可以推迟产品对象的获取


解决 set 循环依赖的原理

**一级缓存 singletonObjects **

image-20230423152153455

作用是保证单例对象仅被创建一次

  • 第一次走 getBean("a") 流程后,最后会将成品 a 放入 singletonObjects 一级缓存
  • 后续再走 getBean("a") 流程时,先从一级缓存中找,这时已经有成品 a,就无需再次创建

一级缓存与循环依赖

image-20230423152409029

一级缓存无法解决循环依赖问题,分析如下

  • 无论是获取 bean a 还是获取 bean b,走的方法都是同一个 getBean 方法,假设先走 getBean("a")
  • 当 a 的实例对象创建,接下来执行 a.setB() 时,需要走 getBean("b") 流程,红色箭头 1
  • 当 b 的实例对象创建,接下来执行 b.setA() 时,又回到了 getBean("a") 的流程,红色箭头 2
  • 但此时 singletonObjects 一级缓存内没有成品的 a,陷入了死循环

**二级缓存 singletonFactories(官方三级缓存) **

image-20230423152834032

解决思路如下:

  • 再增加一个 singletonFactories 缓存
  • 在依赖注入前,即 a.setB() 以及 b.setA() 将 a 及 b 的半成品对象(未完成依赖注入和初始化)放入此缓存
  • 执行依赖注入时,先看看 singletonFactories 缓存中是否有半成品的对象,如果有拿来注入,顺利走完流程

对于上面的图

  • a = new A() 执行之后就会把这个半成品的 a 放入 singletonFactories 缓存,即 factories.put(a)
  • 接下来执行 a.setB(),走入 getBean("b") 流程,红色箭头 3
  • 这回再执行到 b.setA() 时,需要一个 a 对象,有没有呢?有!
  • factories.get() 在 singletonFactories 缓存中就可以找到,红色箭头 4 和 5
  • b 的流程能够顺利走完,将 b 成品放入 singletonObject 一级缓存,返回到 a 的依赖注入流程,红色箭头 6

二级缓存与创建代理

image-20230423153224037

二级缓存无法正确处理循环依赖并且包含有代理创建的场景,分析如下

  • spring 默认要求,在 a.init 完成之后才能创建代理 pa = proxy(a)
  • 由于 a 的代理创建时机靠后,在执行 factories.put(a) 向 singletonFactories 中放入的还是原始对象
  • 接下来箭头 3、4、5 这几步 b 对象拿到和注入的都是原始对象

二级缓存的问题(singletonFactories):依赖注入先发生,创建代理后发生,创建对象时代理对象还没有,即它只能注入那个原始的目标对象

解决办法:把代理对象提前创建,但Spring没有这么做,它还是想代理对象尽可能在最后来创建,即初始化后才创建,只有发生了循环依赖时它才提前创建代理

**三级缓存 earlySingletonObjects(官方二级缓存) **

image-20230423154033542

简单分析的话,只需要将代理的创建时机放在依赖注入之前即可,但 spring 仍然希望代理的创建时机在 init 之后,只有出现循环依赖时,才会将代理的创建时机提前。所以解决思路稍显复杂:

  • 图中 factories.put(fa) 放入的既不是原始对象,也不是代理对象而是工厂对象 fa
  • 当检查出发生循环依赖时,fa 的产品就是代理 pa,没有发生循环依赖,fa 的产品是原始对象 a
  • 假设出现了循环依赖,拿到了 singletonFactories 中的工厂对象,通过在依赖注入前获得了 pa,红色箭头 5
  • 这回 b.setA() 注入的就是代理对象,保证了正确性,红色箭头 7
  • 还需要把 pa 存入新加的 earlySingletonObjects 缓存,红色箭头 6
  • a.init 完成后,无需二次创建代理,从哪儿找到 pa 呢?earlySingletonObjects 已经缓存,蓝色箭头 9
  • 当成品对象产生,放入 singletonObjects 后,singletonFactories 和 earlySingletonObjects 中的对象就没有用处,清除即可

引入三级缓存(earlySingletonObjects),并且还要引入一个工厂才能实现刚才的目的,这个工厂(理解为一个Lambda表达式fa-> pa || a)的作用是产生代理对象或原始对象,它会检查如果你将来发生了循环依赖,它就会提前创建生成代理对象并返回,如果没有发生循环依赖,它还是返回原始对象

set循环依赖演示

image-20230423154514318
  • DEBUG - getSingleton
image-20230423160842182
image-20230423160934610
image-20230423160952450

起点由 refresh 第十一步(finishBeanFactoryInitialization)开始,初始化所有非延迟单例 bean

java
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ...
	beanFactory.preInstantiateSingletons();    
}
@Override
public void preInstantiateSingletons() throws BeansException {
	...
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
         ...
         //非延迟单例 bean 获取   
		getBean(beanName);
		...
	}
}
//核心方法1
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    //从1、2、3级缓存解决set循环依赖的核心方法,allowEarlyReference=true;debug核心点,设置面向all的beanName.equals("a");哪个bean先注册就设置哪个
    //第一次getBean("a"),sharedInstance=null,因为一级二级缓存都没有存储a或其代理对象,三级缓存还未添加
	Object sharedInstance = getSingleton(beanName);
    //进入单例bean的创建步骤
    ...
    return createBean(beanName, mbd, args);
    ...
}
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    ...
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    ...
}
//bean的创建三阶段核心方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    ...
    //bean的实例化
    Object bean = instanceWrapper.getWrappedInstance();
    ...
	//添加bean的三级缓存核心方法,存储Lambda表达式,后续调用getObject时会回调
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    //记录原始bean,后续判断初始化阶段或之前有没有创建代理
	Object exposedObject = bean;
	try {
         //依赖注入阶段
		populateBean(beanName, mbd, instanceWrapper);
		//初始化阶段
         exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
    ...
}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    ...
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        //遍历bean的后处理到AutowiredAnnotationBeanPostProcessor进行注解解析
		PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        ...
    }
    ...
}
  • 循环依赖在依赖注入的关键点 postProcessProperties(...) -> inject(...):AutowiredMethodElement -> resolveMethodArguments(...) -> resolveDependency(...) -> doResolveDependency(...) -> resolveCandidate(...) -> getBean("b");
  • 进入 b 的创建过程,与 a 第一次 getBean 一样,然后依赖注入走到 getBean("a")
  • 第二次getBean("a"),就会进入三级缓存获取 bean 的流程
java
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}
//getSingleton三级缓存获取对象工厂的核心流程
...
synchronized (this.singletonObjects) {
	// Consistent creation of early reference within full singleton lock
	singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null) {
			ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
			if (singletonFactory != null) {
                  //a第一次getBean时将自己到三级缓存里,singletonFactories=[{"a",()->{...}}],所以当获取到a的工厂对象后调用getObject方法就会回调Lambda表达式里的代码块方法getEarlyBeanReference(beanName, mbd, bean)
				singletonObject = singletonFactory.getObject();
				this.earlySingletonObjects.put(beanName, singletonObject);
				this.singletonFactories.remove(beanName);
			}
		}
	}
}
...
java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   ...
         exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
   ...
   return exposedObject;
}
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
 	Object cacheKey = getCacheKey(bean.getClass(), beanName);
    //将准备进入代理的对象引入存入二级缓存,后续在初始化完成后进行代理增强的判断,无需再次创建代理
 	this.earlyProxyReferences.put(cacheKey, bean);
    //将返回代理后的对象:包名.$类名$$EnhancerBySpringCGLIB$$引用地址
 	return wrapIfNecessary(bean, beanName, cacheKey);
}
java
//#doGetBean
...
if (sharedInstance != null && args == null) {
   ...
   beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
...
return adaptBeanInstance(name, beanInstance, requiredType);
//方法跳出 -> resolveCandidate(...) -> resolveDependency -> resolveMethodArguments(...) -> inject(...)
//#doResolveDependency
    ...
    instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    ...
    return result;
	}
	finally {
        //方法返回前执行
	    ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
	}
}
//#resolveDependency
...
    if (result == null) {
      //result为a的代理对象
	  result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
	}
	return result;
...
    
//#inject
    else {
        arguments = resolveMethodArguments(method, bean, beanName);
    }
    if (arguments != null) {
        try {
            ReflectionUtils.makeAccessible(method);
            //反射执行setA注入给B
            method.invoke(bean, arguments);
            //输出:- setA(class 包名.$A$$EnhancerBySpringCGLIB$$5fbc14f4) 
        }
        catch (...) {...}
    }
...
  • b依赖注入完后跳出 populateBean 进入b的初始化过程
  • b整个创建流程走完最后也是方法跳出到resolveCandidate方法,进行a的依赖注入流程,反射执行setB注入给a
  • a的初始化走完,进入第二次缓存检查,防止代理对象的遗漏
java
//doCreateBean
...
//原始对象
Object exposedObject = bean;
	try {
		populateBean(beanName, mbd, instanceWrapper);
         //初始化后对象,因为在初始化阶段a没有进行代理创建,但是b注入a时提前把a的代理对象创建并进行值注入,所以后面进行第二次缓存检查获取代理对象,防止遗漏
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
...
if (earlySingletonExposure) {
    //从二级缓存获取a的代理对象
   Object earlySingletonReference = getSingleton(beanName, false);
   if (earlySingletonReference != null) {
      if (exposedObject == bean) {
          //将a的原始引用指向代理对象引用
         exposedObject = earlySingletonReference;
      }
      ...
   }
}
...
  • set循环依赖 - 二级缓存作用1
image-20230423162034164
java
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
...
    	//bean为原始对象
    	Object bean = instanceWrapper.getWrappedInstance();
		...
             //发生循环依赖,将对象加入三级缓存singletonFactories
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		...
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
             //依赖注入
			populateBean(beanName, mbd, instanceWrapper);
			//初始化后的bean
             exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {...}

		if (earlySingletonExposure) {
             //获取一级和二级缓存是否有该目前的bean,但不会到三级缓存中获取,目的是防止bean提前创建代理后在二级缓存中的遗漏
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
                      //防止二级缓存遗漏,若提前创建了代理直接改变引用即可,否则就是原始对象了(提前创建代理发生在doGetBean一开始调用的getSingleton(beanName),此方法就会在三级缓存singletonFactories对要注入的bean进行提前创建代理,或者说B要注入A时,)
					exposedObject = earlySingletonReference;
				}
                 //初始化阶段就创建代理了,直接返回代理对象
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					...
				}
			}
		}
...
  • set循环依赖 - 二级缓存作用2
image-20230423163506278
  • set循环依赖 - 如何避免重复创建代理
image-20230423163952262

总结

  • 单例 set 方法(包括成员变量)循环依赖,Spring 会利用三级缓存解决,无需额外配置
    • 一级缓存存放成品对象
    • 二级缓存存放发生了循环依赖时的产品对象 (可能是原始 bean,也可能是代理 bean)
    • 三级缓存存放工厂对象,发生循环依赖时,会调用工厂获取产品
    • Spring 期望在初始化时创建代理,但如果发生了循环依赖,会由工厂提前创建代理,后续初始化时就不必重复创建代理
    • 二级缓存的意义在于,如果提前创建了代理对象,在最后的阶段需要从二级缓存中获取此代理对象,作为最终结果
  • 构造方法及多例循环依赖解决办法
    • @Lazy
    • @Scope
    • ObjectFactory & ObjectProvider
    • Provider

4. Spring 事务失效

1. 抛出检查异常导致事务不能正确回滚

  • 问题:出现了数据不一致情况(总金额2000=>1500,被系统吃了500)

  • 原因:Spring 默认只会回滚非检查异常

  • 解法:配置 rollbackFor 属性

    • @Transactional(rollbackFor = Exception.class)
image-20230422140026927

2. 业务方法内自己 try-catch 异常导致事务不能正确回滚

  • 问题:出现了数据不一致情况(总金额2000=>1500,被系统吃了500)

  • 原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉

  • 解法1:异常原样抛出

    • 在 catch 块添加 throw new RuntimeException(e);
  • 解法2:手动设置 TransactionStatus.setRollbackOnly()

    • 在 catch 块添加 TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
image-20230422140710210

3. aop 切面顺序导致导致事务不能正确回滚

  • 原因:事务切面优先级最低,但如果自定义的切面优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出异常,事务也不会回滚

  • 解法1、2:同情况2 中的解法:1、2

  • 解法3:调整切面顺序,在 MyAspect 上添加 @Order(Ordered.LOWEST_PRECEDENCE - 1) (不推荐)

image-20230422141539702

4. 非 public 方法导致的事务失效

  • 原因:Spring 为方法创建代理、添加事务通知、前提条件都是该方法是 public 的;因为Spring中有个检查,它发现你的方法不是public,去读取事务的属性时就会返回null,即不会返回事务的属性,从而不会加这些事务的相关配置

  • 解法1:改为 public 方法

  • 解法2:添加 bean 配置如下(不推荐)

java
@Bean
public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource(false);
}
image-20230422141914663

5. 父子容器导致的事务失效

现在配置了父子容器,WebConfig 对应子容器,AppConfig 对应父容器,发现事务依然失效

  • 原因:子容器扫描范围过大,本来只需扫描controller,但是把service也扫了进来,service虽然有事务注解,但是子容器配置类并没有开启事务配置,因此事务失效
image-20231205214825213
  • 解法1:各扫描各的,不要图简便

  • 解法2:不要用父子容器,所有 bean 放在同一容器

image-20230422143148085

6. ★调用本类方法导致传播行为失效★

java
@Transactional
public void foo(){
    bar();
}
@Transactional
public void bar(){
}
  • 原因:本类方法调用不经过代理,因此无法增强

  • 解法1:依赖注入自己(代理)来调用

  • 解法2:通过 AopContext 拿到代理对象,来调用(代理模式是在运行期间生成一些代理的新的字节码来实现功能的增强)

  • 解法3:通过 CTW(编译时织入),LTW (加载时织入)实现功能增强(原理都是修改类的字节码来实现功能增强)

解法1

java
@Service
public class Service6 {
	@Autowired
	private Service6 proxy; // 本质上是一种循环依赖
    @Transactional
    public void foo()  {
		proxy.bar();
    }
    @Transactional
    public void bar() {
    }
}

解法2,还需要在 AppConfig 上添加 @EnableAspectJAutoProxy(exposeProxy = true)

java
@Service
public class Service6 {
    @Transactional
    public void foo(){
		((Service6) AopContext.currentProxy()).bar();
    }
    @Transactional
    public void bar(){
    }
}
image-20230422143959797

7. @Transactional 没有保证原子行为

java
@Transactional(rollbackFor = Exception.class)
public void transfer(int from, int to, int amount) {
    int fromBalance = accountMapper.findBalanceBy(from);
    logger.debug("更新前查询余额为: {}", fromBalance);
    if (fromBalance - amount >= 0) {
        accountMapper.update(from, -1 * amount);
        accountMapper.update(to, amount);
    }
}

上面的代码实际上是有 bug 的,假设 from 余额为 1000,两个线程都来转账 1000,可能会出现扣减为负数的情况

  • 原因:事务的原子性仅涵盖 insert、update、delete、select … for update 语句,select 方法并不阻塞
image-20210903120436365
  • 如上图所示,红色线程和蓝色线程的查询都发生在扣减之前,都以为自己有足够的余额做扣减
image-20230422144457753

8. ★@Transactional 方法导致的 synchronized 失效★

针对上面的问题,能否在方法上加 synchronized 锁来解决呢?

答案是不行,原因如下:

  • synchronized 保证的仅是目标方法的原子性,环绕目标方法的还有 commit 等操作,它们并未处于 sync 块内
  • 可以参考下图发现,蓝色线程的查询只要在红色线程提交之前执行,那么依然会查询到有 1000 足够余额来转账(实际已经扣过1000了,那么最终结果就是 -1000)
image-20210903120800185
  • 解法1:synchronized 范围应扩大至代理方法调用(DEBUG来Commit)
image-20230422145400664
  • 解法2:使用 select … for update 替换 select(推荐使用数据库层面来解决)
image-20230422145452610

5. Spring MVC 执行流程

概要

我把整个流程分成三个阶段

  • 初始化阶段
  • 匹配阶段
  • 执行阶段

初始化阶段

image-20231206162537789
  1. 在 Web 容器第一次用到 DispatcherServlet 的时候,会创建其对象并执行 init 方法

  2. init 方法内会创建 Spring Web 容器,并调用容器 refresh 方法

  3. refresh 过程中会创建并初始化 SpringMVC 中的重要组件, 例如 MultipartResolver,HandlerMapping,HandlerAdapter,HandlerExceptionResolver、ViewResolver 等

  4. 容器初始化后,会将上一步初始化好的重要组件,赋值给 DispatcherServlet 的成员变量,供后续使用

image-20230422150617027
  • DispatcherServlet 是 SpringMVC 中的一个非常核心的类,由 web 容器(tomcat)创建和初始化,传统的 SpringMVC 跟 Spring 整合的时候还是由 Tomcat 来创建它的,当然,到了 SpringBoot 里,这个 DispatcherServlet 就有可能由 Spring 容器自身来创建和初始化
  • 除 MultipartResovler 可能只有一个实例以外,其他的重要组件同一个类型可能有多个实例对象存在这个 Spring 容器中
  • HandlerMapping 是做请求映射的,就是根据你的请求路径找到一个对应的控制器和它相关的方法来处理这个请求,就是把浏览器的请求映射到我们 Spring 中一个控制器的方法调用上
  • HandlerAdapter 就是负责真正去调用这个控制器的控制方法来处理请求,如果在调用这个控制器的控制方法的过程中出现了异常时由HandlerExceptionResovler来处理异常,最终这个控制方法执行完毕后,就会封装成一个 ModelAndView 对象,但这个对象中的视图可能只包含一个字符串的名字,那我们需要把这个字符串的名字去解析成一个视图对象由 ViewResovler 负责把名字解析成视图对象,视图对象内部就可以根据不同的实现去选择是跳转到JSP还是跳转到一些模板引擎,去执行这个视图的渲染工作
  • 最后的这个 MultipartResovler 并不是必须的,它是用在文件的上传时处理这种 Multipart 格式的表单数据

Spring MVC 的核心组件

  1. DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥。
  2. Handler:处理器,完成具体的业务逻辑,相当于 Servlet 或 Action。
  3. HandlerMapping:DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求映射到不同的 Handler。
  4. HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口。
  5. HandlerExecutionChain:处理器执行链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外设置拦截,可以添加拦截器)。
  6. HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到 JavaBean 等,这些操作都是由 HandlerApater 来完成,开发者只需将注意力集中业务逻辑的处理上,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
  7. ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
  8. ViewResolver:视图解析器,DispatcheServlet 通过它将逻辑视图解析为物理视图,最终将渲染结果响应给客户端。

匹配阶段

  1. 用户发送的请求统一到达前端控制器 DispatcherServlet

  2. DispatcherServlet 遍历所有 HandlerMapping ,找到与路径匹配的处理器

    ① HandlerMapping 有多个,每个 HandlerMapping 会返回不同的处理器对象,谁先匹配,返回谁的处理器。其中能识别 @RequestMapping 的优先级最高

    ② 对应 @RequestMapping 的处理器是 HandlerMethod,它包含了控制器对象和控制器方法信息

    ③ 其中路径与处理器的映射关系在 HandlerMapping 初始化时就会建立好

image-20210903141017502
  1. 将 HandlerMethod 连同匹配到的拦截器,生成调用链对象 HandlerExecutionChain 返回
image-20210903141124911
  1. 遍历HandlerAdapter 处理器适配器,找到能处理 HandlerMethod 的适配器对象,开始调用
image-20210903141204799
image-20230422151134584
  • DispatcherServlet主要职责是作为一个左请求的入口,但是接下来处理请求是交给其他一些处理器对象来完成,它并不负责处理具体的请求,因此接下来会遍历所有的HandlerMapping,借助这个HandlerMapping找到与当前路径能够匹配的处理器,由处理器对象来处理请求,并不是一个请求返回多个处理器,最终只能一个请求由一个处理器对象进行处理,即谁先与当前路径匹配上,就返回谁的处理
  • @RequestMapping对应的处理器对象HandlerMethod,它包含了它属于哪个controller对象以及对应的controller方法的这些信息,通过HandlerMethod可以得到它将来要调用哪个controller对象和调用哪个controller方法,即反射调用

调用阶段

  1. 执行拦截器 preHandle
image-20210903141445870
  1. 由 HandlerAdapter 调用 HandlerMethod

    ① 调用前处理不同类型的参数

    ② 调用后处理不同类型的返回值

image-20210903141658199
  1. 第 2 步没有异常

    ① 返回 ModelAndView

    ② 执行拦截器 postHandle 方法

    ③ 解析视图,得到 View 对象,进行视图渲染

image-20210903141749830
  1. 第 2 步有异常,进入 HandlerExceptionResolver 异常处理流程
image-20210903141844185
  1. 最后都会执行拦截器的 afterCompletion 方法

  2. 如果控制器方法标注了 @ResponseBody 注解,则在第 2 步,就会生成 json 结果,并标记 ModelAndView 已处理,这样就不会执行第 3 步的视图渲染

image-20230426024421958
  • 执行阶段首先会调用执行链中的拦截器的 preHandle 方法,由外到内依次调用,调用这个 preHandle 方法的时候,这个方法会有一个返回值,返回值为真表示放行,会进行后续的调用,为假表示被拦截器拦截下来了,就不会往后走了
  • HandlerAdapter 调用 HandlerMethod,虽然知道哪个bean的哪个方法,但是方法调用之前得给方法准备所有的参数,因为控制器方法的参数是十分复杂的,多种多样,既可以是 Request、Respone、Session之类,也可能是一些模型,model 对象,还有可能是方法的参数来自于请求参数,路径参数,各种情况都有,你得把这些参数进行一个解析,把参数都准备好了,就可以反射调用这个 HandlerMethod 中的 method 方法,通过 method 的反射调用执行 invoke 方法,然后把 bean 传进去,把刚才准备好的参数传入 invoke 方法并执行,这样就完成了控制器方法的一个调用,等调用结束后还要处理返回值,这个控制器方法的返回值也是多种多样,有可能返回的是一个字符串类型,Map 集合,List 集合,或者 JavaBean,都有可能,因此还要对这个返回值进行一个处理,那返回值处理完了,这个调用就暂时结束了
  • 结束之后分成两种情况,一种是没有异常,一种是有异常
    • 没有异常
      1. 把上一步结果返回统一封装成 ModelAndView,不管之前是什么类型(字符串…),最终都会封装成 ModelAndView 对象,此对象里面就包含模型数据,视图相关的信息
      2. 返回了 ModelAndView 对象之后又回到拦截器,这回是调用拦截器的 postHandle 方法,这个 postHandle 方法调用的次序正好和 preHandle 方法调用的次序相反,即由内至外,把所有的 postHandle 也调用一遍后,最终才处理这个 ModelAndView
      3. ModelAndView 处理的时候,第一个要处理的是这个视图,因为前面的调用仅仅返回的是一个字符串的视图名称,而不是一个视图对象,因此要借助一个叫做 ViewResovler 视图解析器,把这种字符串名字解析成一个真正的视图对象,当然,如果返回的直接是视图对象,它就直接用了
      4. 解析好视图之后,它就可以进入这个视图的渲染,它会把模型数据根据视图的实现不同先存储到不同的位置,如 JSP 的实现,它就把模型数据取出来放入到 Request 作用域,接下来转发到 JSP 的视图,JSP 视图里就可以从作用域中取出模型数据,最后渲染生成一个 html 并返回
      5. 等这个视图处理完后,还有一个收尾工作,它最终还会回到我们的拦截器,由内到外的顺序调用 afterCompletion 方法,等所有的 afterCompletion 调用完后,整个的执行流程就结束了
    • 出现了异常
      1. 出现异常之后,ModelAndView 就没有了,而是拿到一个 Exception 的异常对象,它有一个 catch 块可以捕捉到异常对象
      2. 捉住到异常对象以后,DispatcherServlet 里还有一个 HandlerExceptionResolver 成员,它们就是用来处理异常的,按照优先级次序,谁先匹配到这个异常对象谁就来处理,挑出一个 HandlerExceptionResolver 来处理异常
      3. 当然,处理完异常,它也会走到最后的 afterCompletion 方法方法由内向外去逐一调用,这个时候就不会调用 postHandle 方法,因为出现异常了,它就没机会执行这个 postHandle
  • 无论以后有没有异常都会执行到拦截器的 afterCompletion 方法
  • 还有一点,就是如果我们的控制器方法标注了 @ResponseBody 注解,这个时候就不是跳转到视图了,它是要返回这种 Json 数据,即在 HandlerAdapter 调用 HandlerMethod 时,有一个阶段是处理返回值,即在处理返回值的阶段去检查是不是这个方法上标注了 @ResponseBody 注解,如果是的话,它就会标记 ModelAndView 已处理,后续就不会去执行视图渲染了,即在处理返回值阶段的时候生成一个叫 MessageConverter 的消息转换器,生成 Json 作为最终结果返回,就不会走视图渲染的流程,当然,这里的 postHandle 和 afterCompletion 这些拦截器的处理操作还是会执行

总结

Spring MVC的工作流程
  1. 客户端向服务端发送一次请求,这个请求会先到前端控制器 DispatcherServlet(也叫中央控制器)。
  2. DispatcherServlet 接收到请求后会调用 HandlerMapping 处理器映射器。由此得知,该请求该由哪个 Controller 来处理(并未调用 Controller,只是得知)
  3. DispatcherServlet 调用 HandlerAdapter 处理器适配器,告诉处理器适配器应该要去执行哪个 Controller
  4. HandlerAdapter 处理器适配器去执行 Controller 并得到 ModelAndView(数据和视图),并层层返回给 DispatcherServlet
  5. DispatcherServlet 将 ModelAndView 交给 ViewReslover 视图解析器解析,然后返回真正的视图。
  6. DispatcherServlet 将模型数据填充到视图中
  7. DispatcherServlet 将结果响应给客户端

Spring MVC 虽然整体流程复杂,但是实际开发中很简单,大部分的组件不需要开发人员创建和管理,只需要通过配置文件的方式完成配置即可,真正需要开发人员进行处理的只有 Handler(Controller)ViewModel

当然我们现在大部分的开发都是前后端分离,Restful 风格接口,后端只需要返回 Json 数据就行了。


5.1 SpringMVC Restful 执行流程

PS:这是一道全新的八股,毕竟 ModelAndView 这种方式应该没人用了吧?现在都是前后端分离接口,八股也该更新换代了。

我们都知道 Restful 接口,响应格式是 json,这就用到了一个常用注解:@ResponseBody

java
    @GetMapping("/user")
    @ResponseBody
    public User user(){
        return new User(1,"张三");
    }

加入了这个注解后,整体的流程上和使用 ModelAndView 大体上相同,但是细节上有一些不同:

image-20231206192404673
  1. 客户端向服务端发送一次请求,这个请求会先到前端控制器 DispatcherServlet

  2. DispatcherServlet 接收到请求后会调用 HandlerMapping 处理器映射器。由此得知,该请求该由哪个 Controller 来处理

  3. DispatcherServlet 调用 HandlerAdapter 处理器适配器,告诉处理器适配器应该要去执行哪个 Controller

  4. Controller 被封装成了 ServletInvocableHandlerMethod,HandlerAdapter 处理器适配器去执行 invokeAndHandle 方法,完成对 Controller 的请求处理

  5. HandlerAdapter 执行完对 Controller 的请求,会调用 HandlerMethodReturnValueHandler 去处理返回值,主要的过程:

    5.1. 调用 RequestResponseBodyMethodProcessor,创建 ServletServerHttpResponse(Spring 对原生 ServerHttpResponse 的封装)实例

    5.2.使用 HttpMessageConverter 的 write 方法,将返回值写入 ServletServerHttpResponse 的 OutputStream 输出流中

    5.3.在写入的过程中,会使用 JsonGenerator(默认使用 Jackson 框架)对返回值进行 Json 序列化

  6. 执行完请求后,返回的 ModealAndView 为 null,ServletServerHttpResponse 里也已经写入了响应,所以不用关心 View 的处理


6. Spring 注解

lang

lang 中的注解是 Spring 框架内部自己使用的一些注解

  • @NonNull
  • @NonNullApi
  • @NonNullFields
  • @Nullable
  • @UsesSunMisc

事务注解

  • @EnableTransactionManagement,会额外加载 4 个 bean

    • BeanFactoryTransactionAttributeSourceAdvisor 事务切面类
    • TransactionAttributeSource 用来解析事务属性
    • TransactionInterceptor 事务拦截器
    • TransactionalEventListenerFactory 事务监听器工厂
    image-20230422152841010
  • @Transactional


监控

  • @EnableMBeanExport
  • @ManagedAttribute
  • @ManagedMetric
  • @ManagedNotification
  • @ManagedNotifications
  • @ManagedOperation
  • @ManagedOperationParameter
  • @ManagedOperationParameters
  • @ManagedResource

核心

  • @AliasFor是给注解起别名(了解)
  • @Order是用来控制一些bean它们的一些执行顺序,最低优先级=整数最大值

事件、调度、异步

  • @EventListener
  • @TransactionalEventListener
  • @EnableAsync
  • @Async
  • @EnableScheduling
  • @Scheduled
  • @Schedules

切面

  • @EnableAspectJAutoProxy
    • 会加载 AnnotationAwareAspectJAutoProxyCreator,它是一个 bean 后处理器,用来创建代理
    • 如果没有配置 @EnableAspectJAutoProxy,又需要用到代理(如事务)则会使用 InfrastructureAdvisorAutoProxyCreator 这个 bean 后处理器
image-20230422154010262
  • @EnableAspectJAutoProxy是启用我们的AOP这种自动代理,看看它@Import的实现,后面的类型加入 AnnotationAwareAspectJAutoProxyCreator 的 bean 后处理器,这个后处理会在 bean 的初始化后期帮助我们检查看看需不需添加一个代理,如果你的 bean 跟某个切点表达式匹配上了,它就会为你的 bean 生成一个代理对象,最终将代理对象放入单例池去代替掉目标的 target 对象,说白了,它就是帮助我们产生这个代理来协助 AOP 增强的,当然,这个代理的执行时机绝大多数情况都是在初始化之后生成代理的,如果遇到了循环依赖又需要代理的情况,它会让代理的生成提前,在这个依赖注入之前就生成代理
  • @Around、@Before、@After 这些与切面通知相关注解实际上是属于第三方库 AspectJ 提供的,Spring 只是借用了人家第三方的注解,并不是 Spring 自己的

组件扫描与配置类

  • @Component

  • @Controller

  • @Service

  • @Repository

@Component、@Controller、@Service、@Repository 这四个是配合做组件扫描的,标注了这些注解的类将来一旦组件扫描到它了,就会把它纳入到 Spring 的容器管理,跟它们配合使用的还有 @ComponentScan,它可以指定一个起始包名,它就会以这个起始包名开始去扫描这个包以及这个包的所有子孙后代包,扫描这些注解,扫描到就把它们加入到 Spring 的容器管理中

  • @ComponentScan

  • @Conditional(Spring 自身就有的功能,并不是只有 SpringBoot)是在这个组件扫描时做一些条件装配,符合条件的就加入到 Spring 容器中,如果判断条件不成立,即使扫描到了,它也不会加入的,它除了和我们组件扫描时候配合以外,还可以跟这个配置类解析 @Bean时配合使用,也会判断是否满足条件

  • @Configuration

    • 配置类其实相当于一个工厂,标注 @Bean 注解的方法相当于工厂方法
    image-20230422190940503
    • @Bean 不支持方法重载,如果有多个重载方法,仅有一个能入选为工厂方法
    image-20230422191323803
    • @Configuration 默认会为标注的类生成代理,其目的是保证 @Bean 方法相互调用时,仍然能保证其单例特性
    image-20230422191956615
    • @Configuration 中如果含有 BeanFactory 后处理器的 bean 要创建,则实例工厂方法会导致 MyConfig 提前创建,造成其依赖注入失败,解决方法是改用静态工厂方法或直接为 @Bean 的方法参数依赖注入,针对 Mapper 扫描可以改用注解方式
    image-20230422192558594
  • @Bean 是标注在配置类里的那些方法(工厂方法),标注 @Configuration 的配置类(工厂类)来定义 @Bean 方法返回的 bean

  • @Import

    • 四种用法

      ① 引入单个 bean

      ② 引入一个配置类

      ③ 通过 Selector 引入多个类

      ④ 通过 beanDefinition 注册器引入多个类

    image-20230422193333726
    • 解析规则

      • 同一配置类中,@Import 先解析 @Bean 后解析
      • 同名定义,默认后面解析的会覆盖前面解析的
      • 不允许覆盖的情况下,如何能够让 MyConfig(主配置类) 的配置优先? (虽然覆盖方式能解决)
      • 采用 DeferredImportSelector,因为它最后工作,可以简单认为先解析 @Bean,再 Import
    image-20230422215656267

    @Import是导入其他的配置类或普通类;导入其他的一些Selector根据它们返回的bean的名字把它们加入到当前的Spring容器中

  • @Lazy

    • 加在类上,表示此类延迟实例化、初始化
    • 加在方法参数上,此参数会以代理方式注入

    有两个用途,一个用途是标注在类上,表示这个类是延迟初始化和实例化的,即一开始你没有用到的时候,它是不会创建这个标注了 @Lazy 的 bean 的实例,当你第一次用到的时候,才会去创建这个标注了 @Lazy 的 bean;还有一个更重要的用法是用在方法参数上和成员变量上,它可以解决循环依赖问题,即让你的这个依赖注入包括参数的注入,它是推迟执行,会注入一个代理对象,代理对象注入以后就解决了循环依赖,将来等循环依赖这个过程走完,你将来真正用到这个 bean 时,它才会真正创建这个 bean,它是用代理解决了循环依赖,这是它更重要的一个用途

  • @PropertySource 是用来读取一些自定义的 properties 文件,把它们作为键值信息加入到我们 environment 对象里来, environment 就是包含了整个应用程序在运行期间需要的所有键值信息

依赖注入

  • @Autowired 加在方法参数上或成员变量上都可以完成依赖注入
  • @Qualifier 是在依赖注入时,如果同一类型有多个 bean,就会根据名字进行区分
  • @Value 是做值注入的,可以对${}#{}这种内嵌式的符号实现内嵌式的注入

缓存

  • @EnableCaching
  • @CacheConfig
  • @CacheEvict
  • @CachePut
  • @Cacheable
  • @Caching

mvc mapping

  • @RequestMapping 作用是建立我们请求路径跟控制器方法之间的映射关系,将来有一个请求过来的时候它就会根据这个请求路径与我们 @RequestMapping 中的路径进行一个匹配,匹配上了它就知道,接下来应该由匹配成功的标注了 @RequestMapping 注解的方法来处理这个请求,这是它的一个最重要的用途,当然这个注解也可以加在类上,加在类上时当你的这个类有多个控制器方法它们有一个相同的路径前缀时,那么可以把这个相同的路径前缀给它提取出来,放在类上的 @RequestMapping
    • 可以派生多个注解如 @GetMapping 等,@GetMapping 功能跟 @RequestMapping 相同,只不过 method 只能是GET请求,它不会去处理其他的 POST,PUT,DELETE 之类的请求,只认 GET 请求

mvc rest

  • @RequestBody 是处理请求体中的 Json 数据的,把 Json 数据转换为 Java 对象
  • @ResponseBody 是把控制器上返回的 Java 对象转换成 Json 数据,然后写入到响应体,组合 @ResponseBody + @Controller = @RestController
  • @ResponseStatus 是可以控制响应的状态码

mvc 统一处理

  • @ControllerAdvice :如果你做一些统一处理的异常方法,或这个转换器方法,还有这个标注了 @ModelAttribute 的方法 ,都可以放在那种标注了 @ControllerAdvice 的类来达到一个统一处理的目的,当然,我们最常用的是把一些处理异常的方法放在标注了 @ControllerAdvice 的方法中来实现一个异常的统一处理,可以让一个标注了 @ExceptionHandler 的方法来处理异常,它是专门来处理异常方法的,当然,这两个注解结合使用的比较多
  • 标注了 @ExceptionHandler 的方法不一定是放在标注了 @ControllerAdvice 的方法中,也可以放在一个普通的控制器中,放在一个单独的控制器中就相当于是一个局部的异常处理,如果方法在一个标注 @ControllerAdvice 的类中,就表示是一个全局的异常处理
  • @RestControllerAdvice 是一个组合注解,即 @ControllerAdvice + @ResponseBody,将来标注了 @ControllerAdvice 的方法做了异常处理,也会转换为 Json 数据写到响应体里

mvc 参数

  • @RequestHeader 是获取请求头中的参数信息
  • @CookieValue 是获取Cookie的值
  • @PathVariable 是获取请求路径的参数值
  • @RequestParam 是获取真正的请求参数值,就是之后的键值信息,也可以是表单中的请求参数,只要你的请求参数跟方法名称对应上,就可以省略这个@RequestParam,其主要作用是可以设置默认值,即defaultValue属性,如果没有传这个请求参数,可以给它设置一个默认值

转换与格式化

  • @DateTimeFormat是转换日期和时间格式
  • @NumberFormat是转换数字格式的
  • @InitBinder是注册一些自定义的类型转换器的

validation是做这个bean的校验的

  • @Validated 加在 Javabean 上,表示这个 Javabean 将来要做数据校验,至于这个校验规则也是加在 Javabean 的属性上,它是借助一个第三方的注解,比如 @NotEmpty,@NotBlank,@NotNull等,这些注解才真正完成校验规则的,而 @Validated 只是作为一个校验的入口

scope

  • 标注了@ApplicationScop,@RequestScope,@SessionScope这类的注解的类,就可以在Spring容器中里面控制它们的作用域

mvc ajax

  • @CrossOrigin是解决ajax请求的一个跨域问题,原理是在响应头上加一些特殊的头,允许你的这个ajax跨域的这种请求,当然,如果你用的HttpClient的这种客户端就没有这种跨域问题,它只适合用于javaScrip里面使用ajax访问时才会存在跨域问题

boot

auto

  • @SpringBootApplication(每个SpringBoot程序都要加的注解)是一个组合注解,即@EnableAutoConfiguration,@SpringBootConfiguration 和@ ComponentScan)
  • @EnableAutoConfiguration 是去找到一些自动配置类,把这些自动配置类关联的 Bean 都要注册到 Spring 容器当中,这个也是一个组合注解,@AutoConfigurationPackage 和 @Import,@AutoConfigurationPackage 的作用是它所标注的类的包名会被记录下来,放到容器中,将来你要用到这个包名的时候,那么就可以通过一个工具类到容器中找到这个包名
  • @SpringBootConfiguration 是表示一个针对 SpringBoot 的配置类,跟原生的 @Configuration 几乎等价,它跟 @Configuration 区别在哪呢,其实用 @Configuration 标注的,将来一个应用程序可以有多个的配置类,但是 @SpringBootConfiguration 它对应的配置类呢,整个应用程序只可以有这么一个配置类(应用程序类),因为它要根据它断定你的主配置,根据你的主配置类找到我们的应用程序,算是一个入口
image-20230422190402081

condition(对@Conditional的一个扩展)

  • @ConditionalOnClass是当你的类路径下包含某个类时,这个条件才算成立,比如说我要配置数据源,可能希望类路径下有具体的数据源实现类,如有一个driuid的DataSource,这个条件才成立,否则不成立,即检查类路径下如果有某个类存在条件才成立,才会执行后续的装配;classpath 下存在某个 class 时,条件才成立
image-20230422190325299
  • @ConditionalOnMissingBean 是当你的容器中缺失某个 bean 时,条件才成立,它经常作为一些后补的操作,如你没有提供某个 bean,即当你缺失配置某个 bean 时条件就会成立,把一个默认的后补的 bean 添加到 Spring 容器中,这个缺失的条件是根据 bean 的名字来匹配的,如果容器中没有这个 bean 时条件就成立,如果这个 bean 的名字已经存在了,条件就不成立;beanFactory 内不存在某个 bean 时,条件才成立
  • @ConditionalOnProperty 是根据 properties 文件的键值信息,看看是不是做了某些键值的配置,如果这些键值配置了,并且条件相符,条件才算成立,比如你的某个键或值跟这个 @ConditionalOnProperty 中值也一致了,条件才算成立,如果你没有这个相应的键值,条件就不成立;配置文件中存在某个 property(键、值)时,条件才成立

properties

  • @ConfigurationProperties,会将当前 bean 的属性与配置文件中的键值进行绑定

    • @ConfigurationProperties 是把我们 properties 文件中的键值信息跟 JavaBean 的属性进行绑定,属性名称与这个配置文件中键的名称相同,对应的值就会赋值给我们标注了 @ConfigurationProperties 的 Javabean 的属性,相当于简化了一些 bean 的初始化,如果用 @Value 虽然也可以对这个值进行初始化,但是比较复杂,@ConfigurationProperties 在一定程度上可以去简化 @Value 的一些赋值操作
  • @EnableConfigurationProperties 就是启用 @ConfigurationProperties 功能,它也是在 bean 工厂加了一些后处理器,这些后处理器能够识别 @ConfigurationProperties ,一旦识别到它就会执行这个绑定操作,会添加以下两个较为重要的 bean

    • ConfigurationPropertiesBindingPostProcessor,bean 后处理器,在 bean 初始化前调用下面的 binder
    • ConfigurationPropertiesBinder,真正执行绑定操作

7. SpringBoot 自动配置原理

自动配置原理

image-20230423003501071

@SpringBootApplication 是一个组合注解,由 @ComponentScan、@EnableAutoConfiguration 和 @SpringBootConfiguration 组成

  1. @SpringBootConfiguration 与普通 @Configuration 相比,唯一区别是前者要求整个 app 中只出现一次

  2. @ComponentScan

    • excludeFilters - 用来在组件扫描时进行排除,也会排除自动配置类
    image-20230423003533333
  3. @EnableAutoConfiguration 也是一个组合注解,由下面注解组成

    • @AutoConfigurationPackage – 用来记住扫描的起始包,放到容器中,将来要用到包名时可以用一个工具类到容器中找到
    • @Import(AutoConfigurationImportSelector.class) 用来加载 META-INF/spring.factories 中的自动配置类
    image-20230423004955603

为什么不使用 @Import 直接引入自动配置类

有两个原因:

  1. 让主配置类和自动配置类变成了强耦合,主配置类不应该知道有哪些从属配置
  2. 直接用 @Import(自动配置类.class),引入的配置解析优先级较高,自动配置类的解析应该在主配置没提供时作为默认配置

因此,采用了 @Import(AutoConfigurationImportSelector.class)

  • AutoConfigurationImportSelector.class 去读取 META-INF/spring.factories 中的自动配置类,实现了弱耦合。
  • 另外 AutoConfigurationImportSelector.class 实现了 DeferredImportSelector 接口,让自动配置的解析晚于主配置的解析

8. Spring 中的设计模式

1. Spring 中的 Singleton

请大家区分 singleton pattern 与 Spring 中的 singleton bean

  • 根据单例模式的目的 Ensure a class only has one instance, and provide a global point of access to it
  • 显然 Spring 中的 singleton bean 并非实现了单例模式,singleton bean 只能保证每个容器内,相同 id 的 bean 单实例
  • 当然 Spring 中也用到了单例模式,例如
    • org.springframework.transaction.TransactionDefinition#withDefaults
    • org.springframework.aop.TruePointcut#INSTANCE
    • org.springframework.aop.interceptor.ExposeInvocationInterceptor#ADVISOR
    • org.springframework.core.annotation.AnnotationAwareOrderComparator#INSTANCE
    • org.springframework.core.OrderComparator#INSTANCE

单例模式的原始定义是确保一个类只有一个实例,并且提到一个全局的访问点,则Spring中的 Singleton bean 是不符合的,因为你一个 Spring 容器中可以一个类型定义多个实例,只要多个 bean 它们的 id 和名字有可能不一样,则可能有多个实例,而且 Spring 可以有多个容器的,多个容器同一个类也可能有不同的实例,同样的 propertype bean 也不是原型模式


2. Spring 中的 Builder

定义: Separate the construction of a complex object from its representation so that the same construction process can create different representations

它主要的亮点有三处:

  1. 较为灵活的构建产品对象

  2. 在不执行最后 build 方法前,产品对象都不可用

  3. 构建过程采用链式调用,看起来比较爽

Spring 中体现 Builder 模式的地方:(这种以Builder结尾的命名的,一般来讲都可以看作它是实现了这种构建器对象,可以对照着它的定义看一下)

  • org.springframework.beans.factory.support.BeanDefinitionBuilder

  • org.springframework.web.util.UriComponentsBuilder

  • org.springframework.http.ResponseEntity.HeadersBuilder

  • org.springframework.http.ResponseEntity.BodyBuilder

Builder 建造器模式,它用在一个对象建造过程比较复杂,可以用这个构建器跟对象把它俩分离开来,这个构建器负责对象创建前的准备,最终调用它的Builder方法创建最终的产品对象


3. Spring 中的 Factory Method

定义: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses

根据上面的定义,Spring 中的 ApplicationContext 与 BeanFactory 中的 getBean 都可以视为工厂方法,它隐藏了 bean (产品)的创建过程和具体实现;

因为你 getBean 出来有可能是一个接口,但是具体实现你也不知道,它都是在 Spring 的配置文件或配置类 bean (产品)的创建过程和具体实现已经定义好了,并且你怎么构建也不知道,也不用去关心,甚至你不用接口去 getBean 它有可能给你返回的是一个代理,即隐藏了 bean 创建过程和具体实现

Spring 中其它工厂:

  • org.springframework.beans.factory.FactoryBean

  • @Bean 标注的静态方法及实例方法

  • ObjectFactory 及 ObjectProvider

前两种工厂主要封装第三方的 bean 的创建过程,后两种工厂可以推迟 bean 创建,解决循环依赖及单例注入多例等问题

Factory Method工厂方法模式,抛开它的定义,它的核心就是去让我们的接口和实现相分离,去降低耦合,这是它最重要的目的


4. Spring 中的 Adapter

定义: Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces

典型的实现有两处:

  • org.springframework.web.servlet.HandlerAdapter – 因为控制器实现有各种各样,比如有
    • 大家熟悉的 @RequestMapping 标注的控制器实现
    • 传统的基于 Controller 接口(不是 @Controller 注解啊)的实现
    • 较新的基于 RouterFunction 接口的实现
    • 它们的处理方法都不一样,为了统一调用,必须适配为 HandlerAdapter 接口
  • org.springframework.beans.factory.support.DisposableBeanAdapter – 因为销毁方法多种多样,因此都要适配为 DisposableBean 来统一调用销毁方法

Adapter适配器模式,适配器模式的定义是把一个或一套接口转换成另一套调用者所期望的接口


5. Spring 中的 Composite

定义: Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly

典型实现有:

  • org.springframework.web.method.support.HandlerMethodArgumentResolverComposite
  • org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite
  • org.springframework.web.servlet.handler.HandlerExceptionResolverComposite
  • org.springframework.web.servlet.view.ViewResolverComposite

composite 对象的作用是,将分散的调用集中起来,统一调用入口,它的特征是,与具体干活的实现实现的是同一个接口,当调用 composite 对象的接口方法时,其实是委托具体干活的实现来完成

Composite 组合模式,它的作用是将分散的调用集中起来,统一调用入口,如在 SpringMVC 中,在调用某个控制器方法前都要给它准备各种各样的参数,不同的参数它的来源是不一样的,获取方式也不一样,如有的是从路径中获取参数,有的是从请求参数获取信息,有的是要生成一个 Model 模型对象作为参数,有的是从传统的 request,response 中获取参数,所以这种不同的参数的解析也是不一样的,这么多参数的解析器,我们要把它们的调用统一起来,我们就提供一个 HandlerMethodArgumentResloverComposite,即参数解析器的组合器,将来只需要调用组合器就行,组合器里有个集合,这个集合里有各种各样的参数解析器,这样就把分散的调用集中起来,统一调用入口,它的特征是与具体干活的实现实现的是同一个 HandlerMethodArgumentReslover 接口,当调用 composite 组合器对象的接口方法时,其实是委托具体干活的实现来完成的


6. Spring 中的 Decorator

定义: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality

典型实现:

  • org.springframework.web.util.ContentCachingRequestWrapper

Decorator 装饰器模式,它的定义是对一个对象动态地去增加一些职责和功能,它主要解决这种用子类扩展方式来实现这种功能增强的问题,因为子类去实现功能增强最大的问题是子类不管用不用的到,它都得把父类的方法继承过来,即继承了很多它用不上的父类方法,装饰器就可以避免这个问题,它跟代理模式的定义很像,也是做功能增强,但做功能增强的实际上不是代理对象,是那些通知(环绕通知之类的),代理其实只起到一个入口的作用,代理只起到对目标对象和目标方法提供一个统一入口的作用,把它们结合起来


7. Spring 中的 Proxy

定义: Provide a surrogate or placeholder for another object to control access to it

装饰器模式注重的是功能增强,避免子类继承方式进行功能扩展,而代理模式更注重控制目标的访问

典型实现:

  • org.springframework.aop.framework.JdkDynamicAopProxy

    • 用jdk动态代理的方式生成最终的代理对象,它的限制是要求你的目标对象必须实现一个接口,那生成的代理也是针对这个接口代理
  • org.springframework.aop.framework.ObjenesisCglibAopProxy

    • 既可以针对接口代理,也可以生成一个子类作为代理,Objenesis是做补充的(提供一个无参构造),这种如果你的目标它没有无参构造,那它在创建这个目标对象时就创建不了,它必须让目标提供一个无参构造
    • Objenesis相当于一个小工具,即使你的目标只有一些带参构造,没有无参构造,它也可以生成一个空空如也的对象,让这个代理能够创建成功

Proxy代理模式,它原本的定义是对另外的对象提供一个代理或者占位用来控制对这个对象的访问,即侧重于对这个目标对象的控制和访问,而不是侧重于对目标对象做功能增强的


8. Spring 中的 Chain of Responsibility

定义: Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it

典型实现:

  • org.springframework.web.servlet.HandlerInterceptor

Chain of Responsibility责任链模式,它的定义是将来可以有多个请求的处理对象,把这多个请求的处理对象串成一个链,每个对象都有机会处理这个请求,这个请求就会沿着这个处理链依次向后传递,直到遇到一个能够处理它的对象为止,根据这个定义,SpringMVC的HandlerInterceptor拦截器是符合这个定义的,我们使用拦截器的时候都知道,多个拦截器都会和最终的这个控制器方法形成一个调用链,这个调用链其实就是我们这里的责任链,请求会沿着这个调用链,先给调用链里第一个拦截器,第一个拦截器处理完后放行了就交给第二个拦截器,以此类推,最终到达我们的这个控制器方法来调用它,这就是拦截器的一个典型体现


9. Spring 中的 Observer

定义: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically

典型实现:

  • org.springframework.context.ApplicationListener
  • org.springframework.context.event.ApplicationEventMulticaster
  • org.springframework.context.ApplicationEvent

Observer观察者模式,作用就是用来解耦的,它主要体现在Spring它实现了这种ApplicationListener监听器(接收事件),ApplicationEventMulticaster事件广播器(发生事件),想当于把发送者和接收者进行一个解耦,还有一个ApplicationEvent对象


10. Spring 中的 Strategy

定义: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it

典型实现:

  • org.springframework.beans.factory.support.InstantiationStrategy

  • org.springframework.core.annotation.MergedAnnotations.SearchStrategy

    • 查找注解的时候,它是要到当前类查找还是要考虑它的父类呢,就用到多种策略方式
  • org.springframework.boot.autoconfigure.condition.SearchStrategy

    • 做条件判断的时候,同样的条件判断是看看你的这个bean是当前容器里还是在这个父容器里呢,还是在所有容器里都去找呢,也是有一个搜索的策略

11. Spring 中的 Template Method

定义: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure

典型实现:

  • 大部分以 Template 命名的类,如 JdbcTemplate,TransactionTemplate
  • 很多以 Abstract 命名的类,如 AbstractApplicationContext

To Be Continued.
面试笔录
Redis 从入门到实战