摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

目录

一、增加SPEL语言的支持

二、增加属性注册编辑器

1. 使用自定义属性编辑器

2. 注册Spring自带的属性编辑器CustomDateEditor

3. 添加 ApplicationContextAwareProcessor 处理器

4. 设置忽略依赖

5. 注册依赖

在进入prepareBeanFactory前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开。

  1. /**
  2. * Configure the factory's standard context characteristics,
  3. * such as the context's ClassLoader and post-processors.
  4. * @param beanFactory the BeanFactory to configure
  5. */
  6. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  7. // Tell the internal bean factory to use the context's class loader etc.
  8. // 设置beanFactory的classLoader为当前context的classLoader
  9. beanFactory.setBeanClassLoader(getClassLoader());
  10. // 设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,
  11. // 默认可以使用#{bean.xxx}的形式来调用相关属性值
  12. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  13. // 为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
  14. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  15.  
  16. // Configure the bean factory with context callbacks.
  17. // 添加BeanPostProcessor
  18. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  19. // 设置了几个忽略自动装配的接口
  20. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  21. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  22. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  23. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  24. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  25. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  26.  
  27. // BeanFactory interface not registered as resolvable type in a plain factory.
  28. // MessageSource registered (and found for autowiring) as a bean.
  29. // 设置了几个自动装配的特殊规则
  30. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  31. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  32. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  33. beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  34.  
  35. // Register early post-processor for detecting inner beans as ApplicationListeners.
  36. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  37.  
  38. // Detect a LoadTimeWeaver and prepare for weaving, if found.
  39. // 增加对AspectJ的支持
  40. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  41. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  42. // Set a temporary ClassLoader for type matching.
  43. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  44. }
  45.  
  46. // Register default environment beans.
  47. // 添加默认的系统环境bean
  48. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
  49. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  50. }
  51. if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
  52. beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  53. }
  54. if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
  55. beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  56. }
  57. }

上面函数中主要进行了几个方面的扩展。

  • 增加对SPEL语言的支持。
  • 增加对属性编辑器的支持。
  • 增加对一些内置类,比如EnvironmentAvare、MessageSourceAware的信息注入。
  • 设置了依赖功能可忽略的接口。
  • 注册一些固定依赖的属性。
  • 增加对AspectJ的支持。
  • 将相关环境变量及属性注册以单例模式注册。

可能读者不是很理解每个步骤的具体含义,接下来我们会对各个步骤进行详细地分析。

一、 增加SPEL语言的支持

Spring 表达式语言全称为 “Spring Expression Language”,缩写为 “SpEL”,类似于Struts 2x 中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等, 并且能与Spring功能完美整合,比如能用  来配置bean定义。SpEL是单独模块,只依赖于core 模块,不依赖于其他模块,可以单独使用。

SpEL使用#{...}为定界符,所有在花括号中的字符都将被认为是SpEL,使用格式如下:

  1. <bean id = "saxophone" value = "com.xxx.xxx.Xxx"/>
  2. <bean >
  3. <property name="instrument" value="#{saxophone}"/>
  4. <bean/>

相当于:

  1. <bean id = "saxophone" value = "com.xxx.xxx.Xxx"/>
  2. <bean >
  3. <property name="instrument" ref="saxophone"/>
  4. <bean/>

当然,上面只是列举了其中最简单的使用方式,SPEL功能非常强大,使用好可以大大提高开发效率,这里只为唤起读者的记忆来帮助我们理解源码,有兴趣的读者可以进一步深入研究。

在源码中通过代码beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注册语言解析器,就可以对SPEL进行解析了,那么在注册解析器后 Spring 又是在什么时候调用这个解析器进行解析呢?

之前我们讲解过 Spring 在 bean 进行初始化的时候会有属性填充的一步,而在这一步中 Spring 会调用AbstractAutowireCapableBeanFactory类的 applyPropertyValues 函数来完成功能。就在这个函数中,会通过构造 BeanDefinitionValueResolver 类型实例 valueResolver 来进行属性值的解析。同时,也是在这个步骤中一般通过 AbstractBeanFactory中的 evaluateBeanDefinitionString 方法去完成 SPEL 的解析。

  1. /**
  2. * Evaluate the given String as contained in a bean definition,
  3. * potentially resolving it as an expression.
  4. * @param value the value to check
  5. * @param beanDefinition the bean definition that the value comes from
  6. * @return the resolved value
  7. * @see #setBeanExpressionResolver
  8. */
  9. @Nullable
  10. protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
  11. if (this.beanExpressionResolver == null) {
  12. return value;
  13. }
  14.  
  15. Scope scope = null;
  16. if (beanDefinition != null) {
  17. String scopeName = beanDefinition.getScope();
  18. if (scopeName != null) {
  19. scope = getRegisteredScope(scopeName);
  20. }
  21. }
  22. return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
  23. }

当调用这个方法时会判断是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在Spring的expression的包内,这里不做过多解释。我们通过查看对evaluateBeanDefinitionString方法的调用层次可以看出,应用语言解析器的调用主要是在解析依赖注入bean的时候,以及在完成bean的初始化和属性获取后进行属性填充的时候。

二、增加属性注册编辑器

在Spring DI注入的时候可以把普通属性注入进来,但是像Date类型就无法被识别。例如:

  1. public class UserManager {
  2.  
  3. private Date dateValue;
  4.  
  5. public Date getDateValue() {
  6. return dateValue;
  7. }
  8.  
  9. public void setDateValue(Date dateValue) {
  10. this.dateValue = dateValue;
  11. }
  12.  
  13. @Override
  14. public String toString() {
  15. return "dataValue: " + dateValue;
  16. }
  17. }

上面代码中,需要对日期型属性进行注入:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6.  
  7. <bean id="userManager" class="org.cellphone.uc.UserManager">
  8. <property name="dateValue">
  9. <value>2018-07-29</value>
  10. </property>
  11. </bean>
  12. </beans>

测试代码:

  1. public static void main(String[] args) {
  2. ApplicationContext context = new ClassPathXmlApplicationContext("spring/beans-test.xml");
  3. UserManager manager = (UserManager) context.getBean("userManager");
  4. System.out.println(manager);
  5. }

如果直接这样使用,程序则会报异常,类型转换不成功。因为在UserManager中的dataValue属性是Date类型的,而在XML中配置的确实String类型的,所以当然会报异常。

Spring针对此问题提供了两种解决方法。

1. 使用自定义属性编辑器

使用自定义属性编辑器,通过继承PropertyEditorSupport,重写setAsText方法,具体步骤如下。

(1)编写自定义的属性编辑器。

  1. public class DatePropertyEditor extends PropertyEditorSupport {
  2.  
  3. private String format = "yyyy-MM-dd";
  4.  
  5. public void setFormat(String format) {
  6. this.format = format;
  7. }
  8.  
  9. @Override
  10. public void setAsText(String text) throws IllegalArgumentException {
  11. System.out.println("text: " + text);
  12. SimpleDateFormat sdf = new SimpleDateFormat(format);
  13. try {
  14. Date d = sdf.parse(text);
  15. this.setValue(d);
  16. } catch (ParseException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }

(2)将自定义属性编辑器注册到Spring中。

  1. <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  2. <property name="customEditors">
  3. <map>
  4. <entry key="java.util.Date" value="org.cellphone.uc.DatePropertyEditor"/>
  5. </map>
  6. </property>
  7. </bean>

在配置文件中引入类型为org.springframework.beans.factory.config.CustomEditorConfigurer的bean,并在属性customEditors中加入自定义的属性编辑器,其中key为属性编辑器所对应的类型。通过这样的配置,当Spring在注入bean的属性时一旦遇到了java.util.Date类型的属性会自动调用自定义的DatePropertyEditor解析器进行解析,并用解析结果代替配置属性进行注入。

2. 注册Spring自带的属性编辑器CustomDateEditor

通过注册Spring自带的属性编辑器CustomDateEditor,具体步骤如下:

(1)定义属性编辑器。

  1. public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
  2. @Override
  3. public void registerCustomEditors(PropertyEditorRegistry registry) {
  4. registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
  5. }
  6. }

(2)注册到Spring中。

  1. <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  2. <property name="propertyEditorRegistrars">
  3. <list>
  4. <bean class="org.cellphone.uc.DatePropertyEditorRegistrar"></bean>
  5. </list>
  6. </property>
  7. </bean>

通过在配置文件中将自定义的DatePropertyEditorRegistrar注册进入org.springframework.beans.factory.config.CustomEditorConfigurer 的 propertyEditorRegistrars 属性中,可以具有与方法 1 同样的效果。

我们了解了自定义属性编辑器的使用,但是,似乎这与本节中围绕的核心代码beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))并无联系,因为在注册自定义属性编辑器的时候使用的是 ResourceEditorRegistrar的registerCustomEditors方法,而这里使用的是ConfigurableListableBeanFactory的addPropertyEditorRegistrar方法。我们不妨深入探索一下 ResourceEditorRegistrar 的内部实现,在 ResourceEditorRegistrar 中,我们最关心的方法是 registerCustomEditors 。

  1. /**
  2. * Populate the given {@code registry} with the following resource editors:
  3. * ResourceEditor, InputStreamEditor, InputSourceEditor, FileEditor, URLEditor,
  4. * URIEditor, ClassEditor, ClassArrayEditor.
  5. * <p>If this registrar has been configured with a {@link ResourcePatternResolver},
  6. * a ResourceArrayPropertyEditor will be registered as well.
  7. * @see org.springframework.core.io.ResourceEditor
  8. * @see org.springframework.beans.propertyeditors.InputStreamEditor
  9. * @see org.springframework.beans.propertyeditors.InputSourceEditor
  10. * @see org.springframework.beans.propertyeditors.FileEditor
  11. * @see org.springframework.beans.propertyeditors.URLEditor
  12. * @see org.springframework.beans.propertyeditors.URIEditor
  13. * @see org.springframework.beans.propertyeditors.ClassEditor
  14. * @see org.springframework.beans.propertyeditors.ClassArrayEditor
  15. * @see org.springframework.core.io.support.ResourceArrayPropertyEditor
  16. */
  17. @Override
  18. public void registerCustomEditors(PropertyEditorRegistry registry) {
  19. ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
  20. doRegisterEditor(registry, Resource.class, baseEditor);
  21. doRegisterEditor(registry, ContextResource.class, baseEditor);
  22. doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
  23. doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
  24. doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
  25. doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
  26. doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
  27. doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
  28.  
  29. ClassLoader classLoader = this.resourceLoader.getClassLoader();
  30. doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
  31. doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
  32. doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
  33.  
  34. if (this.resourceLoader instanceof ResourcePatternResolver) {
  35. doRegisterEditor(registry, Resource[].class,
  36. new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
  37. }
  38. }
  39.  
  40. /**
  41. * Override default editor, if possible (since that's what we really mean to do here);
  42. * otherwise register as a custom editor.
  43. */
  44. private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
  45. if (registry instanceof PropertyEditorRegistrySupport) {
  46. ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
  47. }
  48. else {
  49. registry.registerCustomEditor(requiredType, editor);
  50. }
  51. }

在doRegisterEditor函数中,可以看到在之前提到的自定义属性中使用的关键代码: registry.registerCustomEditor(requiredType, editor),回过头来看 ResourceEditorRegistrar 类的 registerCustomEditors方法的核心功能,其实无非是注册了一系列的常用类型的属性编辑器,例 如,代码 doRegisterEditor(registry,Class.class, new ClassEditor(classLoader))实现的功能就是注册 Class类对应的属件编辑器。那么,注册后,一旦某个实体bean中存在一些Class类型的属性, 那么Spring会调用ClassEditor将配置中定义的String类型转换为Class类型并进行陚值。

分析到这里,我们不禁有个疑问,虽说ResourceEditorRegistrar类的registerCustomEditors方法实现了批量注册的功能,但是beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())仅仅是注册了 ResourceEditorRegistrar 实例,却并没有调用ResourceEditorRegistrar 的registerCustomEditors方法进行注册,那么到底是在什么时候进行注册的呢?进一步查看 ResourceEditorRegistrar 的 registerCustomEditors 方法的调用层次结构,如下图所示。

发现在AbstractBeanFactory中的registerCustomEditors方法中被调用过,继续查看AbstractBeanFactory中的registerCustomEditors方法的层次结构,如下图所示。

其中我们看到一个方法是我们熟悉的,就是AbstractBeanFactory类中的initBeanWrapper 方法,这是在bean初始化时使用的一个方法,之前巳经使用过大量的篇幅进行讲解,主要是在将BeanDefinition转换为BeanWrapper后用于对属件的填充。到此,逻辑已经明了,在bean的初始化后会调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析了。

既然提到了 BeanWrapper,这里也有必要强调下,Spring中用于封装bean的是BeanWrapper 类型,而它又间接继承了 PropertyEditorRegistry类型,也就是我们之前反复看到的方法参数 PropertyEditorRegistry registry,其实大部分情况下都是 BeanWrapper,对于 BeanWrapper 在 Spring 中的默认实现是 BeanWrapperlmpl,而 BeanWrapperlmpl 除了实现 BeanWrapper 接门外还继承了 PropertyEdhorRegistrySupport,在 PropertyEditorRegistrySupport 中有这样一个方法:

  1. /**
  2. * Actually register the default editors for this registry instance.
  3. */
  4. private void createDefaultEditors() {
  5. this.defaultEditors = new HashMap<>(64);
  6.  
  7. // Simple editors, without parameterization capabilities.
  8. // The JDK does not contain a default editor for any of these target types.
  9. this.defaultEditors.put(Charset.class, new CharsetEditor());
  10. this.defaultEditors.put(Class.class, new ClassEditor());
  11. this.defaultEditors.put(Class[].class, new ClassArrayEditor());
  12. this.defaultEditors.put(Currency.class, new CurrencyEditor());
  13. this.defaultEditors.put(File.class, new FileEditor());
  14. this.defaultEditors.put(InputStream.class, new InputStreamEditor());
  15. this.defaultEditors.put(InputSource.class, new InputSourceEditor());
  16. this.defaultEditors.put(Locale.class, new LocaleEditor());
  17. this.defaultEditors.put(Path.class, new PathEditor());
  18. this.defaultEditors.put(Pattern.class, new PatternEditor());
  19. this.defaultEditors.put(Properties.class, new PropertiesEditor());
  20. this.defaultEditors.put(Reader.class, new ReaderEditor());
  21. this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
  22. this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
  23. this.defaultEditors.put(URI.class, new URIEditor());
  24. this.defaultEditors.put(URL.class, new URLEditor());
  25. this.defaultEditors.put(UUID.class, new UUIDEditor());
  26. this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());
  27.  
  28. // Default instances of collection editors.
  29. // Can be overridden by registering custom instances of those as custom editors.
  30. this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
  31. this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
  32. this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
  33. this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
  34. this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
  35.  
  36. // Default editors for primitive arrays.
  37. this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
  38. this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
  39.  
  40. // The JDK does not contain a default editor for char!
  41. this.defaultEditors.put(char.class, new CharacterEditor(false));
  42. this.defaultEditors.put(Character.class, new CharacterEditor(true));
  43.  
  44. // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
  45. this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
  46. this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
  47.  
  48. // The JDK does not contain default editors for number wrapper types!
  49. // Override JDK primitive number editors with our own CustomNumberEditor.
  50. this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
  51. this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
  52. this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
  53. this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
  54. this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
  55. this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
  56. this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
  57. this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
  58. this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
  59. this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
  60. this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
  61. this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
  62. this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
  63. this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
  64.  
  65. // Only register config value editors if explicitly requested.
  66. if (this.configValueEditorsActive) {
  67. StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
  68. this.defaultEditors.put(String[].class, sae);
  69. this.defaultEditors.put(short[].class, sae);
  70. this.defaultEditors.put(int[].class, sae);
  71. this.defaultEditors.put(long[].class, sae);
  72. }
  73. }

具体的调用方法我们就不去深究了,但是至少通过这个方法我们已经知道了在Spring中定义了上面一系列常用的属性编辑器使我们可以方便地进行配置。如果我们定义的bean中的某个属性的类型不在上面的常用配置中的话,才需要我们进行个性化属性编辑器的注册。

3. 添加 ApplicationContextAwareProcessor 处理器

了解了属性编辑器的使用后,接下来我们继续通过AbstractApplicationContext的 prepareBeanFactory 方法的主线来进行函数跟踪。对于 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))其实主要目的就是注册个 BneaPostProcessor,而真正的逻辑还是在 ApplicationContextAwareProcessor 中。

ApplicationContextAwareProcessor 实现 BeanPostProcessor 接口,我们回顾下之前讲过的内容,在bean实例化的时候,也就是Spring激活bean的init-method的前后,会调用BeanPostProcessor 的 postProcessBeforelnitialization 方法和 postProcessAfterlnitialization 方法。问样,对于ApplicationContextAwareProcessor我们也关心这两个方法。

对于postProcessAfterlnitialization 方法,在ApplicationContextAwareProcessor 中并没有做过多逻辑处理。

  1. @Override
  2. public Object postProcessAfterInitialization(Object bean, String beanName) {
  3. return bean;
  4. }

那么,我们重点看一下postProcessBeforelnitialization 方法。

  1. @Override
  2. @Nullable
  3. public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
  4. AccessControlContext acc = null;
  5.  
  6. if (System.getSecurityManager() != null &&
  7. (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
  8. bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
  9. bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
  10. acc = this.applicationContext.getBeanFactory().getAccessControlContext();
  11. }
  12.  
  13. if (acc != null) {
  14. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  15. invokeAwareInterfaces(bean);
  16. return null;
  17. }, acc);
  18. }
  19. else {
  20. invokeAwareInterfaces(bean);
  21. }
  22.  
  23. return bean;
  24. }
  25.  
  26. private void invokeAwareInterfaces(Object bean) {
  27. if (bean instanceof Aware) {
  28. if (bean instanceof EnvironmentAware) {
  29. ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
  30. }
  31. if (bean instanceof EmbeddedValueResolverAware) {
  32. ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  33. }
  34. if (bean instanceof ResourceLoaderAware) {
  35. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  36. }
  37. if (bean instanceof ApplicationEventPublisherAware) {
  38. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  39. }
  40. if (bean instanceof MessageSourceAware) {
  41. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  42. }
  43. if (bean instanceof ApplicationContextAware) {
  44. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  45. }
  46. }
  47. }

postProcessBeforelnitialization 方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,我们或许已经或多或少了解了Spring的用意,实现这些Aware接口的bean在被初始化之后,可以取得一些对应的资源。

4. 设置忽略依赖

当Spring 将 ApplicationContextAwareProcessor 注册后,那么在 invokeAwarelnterfaces 方法中间接调用的 Aware 类已经不是普通的 bean 了,如 ResourceLoaderAware、ApplicationEventPublisher Aware等,那么当然需要在Spring做bean的依赖注入的时候忽略它们。而ignoreDependencylnterfece的作用正是在此。

  1. // 设置了几个忽略自动装配的接口
  2. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  3. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  4. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  5. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  6. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  7. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

5. 注册依赖

Spring中有了忽略依赖的功能,当然也必不可少地会有注册依赖的功能。

  1. // 设置了几个自动装配的特殊规则
  2. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  3. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  4. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  5. beanFactory.registerResolvableDependency(ApplicationContext.class, this);

当注册了依赖解析后,例如当注册了对BeanFactory.class的解析依赖后,当bean的属性注入的时候,一旦检测到属性为BeanFactory类型便会将beanFactory的实例注人进去。

Spring源码分析(二十二)功能扩展的更多相关文章

  1. Spring源码分析(十二)FactoryBean的使用

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 一般情况下,Spring通过反射机制利用bean的class属性指定实现 ...

  2. Spring源码分析(十八)创建bean

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.创建bean的实例 1. autowireConstructor 2 ...

  3. spark 源码分析之十二 -- Spark内置RPC机制剖析之八Spark RPC总结

    在spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv中,剖析了NettyRpcEnv的创建过程. Dispatcher.NettyStreamManager.T ...

  4. Spring源码分析(十九)容器的功能扩展概览

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单 ...

  5. Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析

    什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保持连接的存活,还有监控另一边服务的可用性等. 心跳包的作用 保活Q:为什么说心跳机制能 ...

  6. Android源码分析(十二)-----Android源码中如何自定义TextView实现滚动效果

    一:如何自定义TextView实现滚动效果 继承TextView基类 重写构造方法 修改isFocused()方法,获取焦点. /* * Copyright (C) 2015 The Android ...

  7. ABP源码分析三十二:ABP.SignalR

    Realtime Realtime是ABP底层模块提供的功能,用于管理在线用户.它是使用SignalR实现给在线用户发送通知的功能的前提 IOnlineClient/OnlineClient: 封装在 ...

  8. ABP源码分析四十二:ZERO的身份认证

    ABP Zero模块通过自定义实现Asp.Net Identity完成身份认证功能, 对Asp.Net Identity做了较大幅度的扩展.同时重写了ABP核心模块中的permission功能,以实现 ...

  9. Vue.js 源码分析(三十二) 总结

    第一次写博客,坚持了一个多月时间,Vue源码分析基本分析完了,回过头也看也漏了一些地方,比如双向绑定里的观察者模式,也可以说是订阅者模式,也就是Vue里的Dep.Watcher等这些函数的作用,网上搜 ...

  10. Spring源码分析(十六)准备创建bean

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring ...

随机推荐

  1. 关系型数据库基本概念及MySQL简述

    数据库基本概念">关系型数据库基本概念 数据库: 对大量信息进行管理的高效解决方案. 按照数据结构来组织.存储和管理数据的库. 数据库系统(DBS,DATABASE SYSTEM): ...

  2. java获取当月天数,指定年月的天数,指定日期获取对应星期 .

    package huolongluo.family.util; import java.text.SimpleDateFormat; import java.util.Calendar; import ...

  3. 分布式部署下的报表调用 API调用 权限问题以及性能方案

     背景描述: 客户的实际情况是需要在具体系统构架前,通过与厂商讨论确定最终的系统架构方案. 需求是客户自己有管理系统,希望建立一个独立的报表服务器,该报表服务器可以对多个管理系统提供报表服务,不知 ...

  4. centos7 安装mariadb最新版并配置

    打开http://mirrors.aliyun.com/,查找mariadb,然后拼装地址http://mirrors.aliyun.com/mariadb/yum打开,点开你想要的版本,选择你的操作 ...

  5. 安装nvm之后node不可用,“node”不是内部或外部命令,也不是可运行的程序或批处理文件(ng)

    安装nvm: 1.下载nvm压缩包地址:https://github.com/coreybutler/nvm-windows/releases 2.下载后解压在目标文件夹中,我这里是H:\applic ...

  6. zabbix系列之六——安装后配置二Items

    https://www.zabbix.com/documentation/3.4/manual/config/items/itemtypes/snmp 1Items 1.1creating items ...

  7. springMVC入门-02

    本节会在上节基础上讨论springMVC如何传值的问题. 在添加dispatcherServlet之后,拦截器会将url中的参数拦截下来,使之可以在controller中使用.以下代码就是在前台输入u ...

  8. swift版的GCD封装

    swift版的GCD封装 说明 本人针对swift封装了GCD,包括GCDQueue,GCDGroup,GCDTimer以及GCDSemaphore,使用较为便利. 源码 https://github ...

  9. 安装oracle 11g时,报启动服务出现错误,找不到OracleMTSRecoveryService的解决方法

    很多人在安装orcl数据库时,出现很多报错,我也不例外,因上次数据库出现问题,无法修复,只能从新安装,无奈的是,安装时报启动服务出现错误,找不到OracleMTSRecoveryService错MMP ...

  10. Windows下Git使用报错:warning:LF will be replaced by CRLF in ××××.××

    Windows下Git使用报错: warning:LF will be replaced by CRLF in ××××.××(文件名) The file will have its original ...