spring源码分析(二十二)功能扩展

wuxiaofeng      2022-04-06     177

关键词:

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

 

目录

一、增加SPEL语言的支持

二、增加属性注册编辑器

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

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

3. 添加 ApplicationContextAwareProcessor 处理器

4. 设置忽略依赖

5. 注册依赖

 

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

/**
 * 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) {
    // Tell the internal bean factory to use the context‘s class loader etc.
    // 设置beanFactory的classLoader为当前context的classLoader
    beanFactory.setBeanClassLoader(getClassLoader());
    // 设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,
    // 默认可以使用#{bean.xxx}的形式来调用相关属性值
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    // 添加BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 设置了几个忽略自动装配的接口
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 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);

    // Register early post-processor for detecting inner beans as ApplicationListeners.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    // 增加对AspectJ的支持
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    // 添加默认的系统环境bean
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

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

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

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

 一、 增加SPEL语言的支持

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

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

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

相当于:

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

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

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

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

/**
 * Evaluate the given String as contained in a bean definition,
 * potentially resolving it as an expression.
 * @param value the value to check
 * @param beanDefinition the bean definition that the value comes from
 * @return the resolved value
 * @see #setBeanExpressionResolver
 */
@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
    if (this.beanExpressionResolver == null) {
        return value;
    }

    Scope scope = null;
    if (beanDefinition != null) {
        String scopeName = beanDefinition.getScope();
        if (scopeName != null) {
            scope = getRegisteredScope(scopeName);
        }
    }
    return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}

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

二、增加属性注册编辑器

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

public class UserManager {

    private Date dateValue;

    public Date getDateValue() {
        return dateValue;
    }

    public void setDateValue(Date dateValue) {
        this.dateValue = dateValue;
    }

    @Override
    public String toString() {
        return "dataValue: " + dateValue;
    }
}

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userManager" class="org.cellphone.uc.UserManager">
        <property name="dateValue">
            <value>2018-07-29</value>
        </property>
    </bean>
</beans>

测试代码:

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

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

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

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

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

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

public class DatePropertyEditor extends PropertyEditorSupport {

    private String format = "yyyy-MM-dd";

    public void setFormat(String format) {
        this.format = format;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        System.out.println("text: " + text);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            Date d = sdf.parse(text);
            this.setValue(d);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

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

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date" value="org.cellphone.uc.DatePropertyEditor"/>
        </map>
    </property>
</bean>

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

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

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

(1)定义属性编辑器。

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

(2)注册到Spring中。

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <bean class="org.cellphone.uc.DatePropertyEditorRegistrar"></bean>
        </list>
    </property>
</bean>

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

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

/**
 * Populate the given {@code registry} with the following resource editors:
 * ResourceEditor, InputStreamEditor, InputSourceEditor, FileEditor, URLEditor,
 * URIEditor, ClassEditor, ClassArrayEditor.
 * <p>If this registrar has been configured with a {@link ResourcePatternResolver},
 * a ResourceArrayPropertyEditor will be registered as well.
 * @see org.springframework.core.io.ResourceEditor
 * @see org.springframework.beans.propertyeditors.InputStreamEditor
 * @see org.springframework.beans.propertyeditors.InputSourceEditor
 * @see org.springframework.beans.propertyeditors.FileEditor
 * @see org.springframework.beans.propertyeditors.URLEditor
 * @see org.springframework.beans.propertyeditors.URIEditor
 * @see org.springframework.beans.propertyeditors.ClassEditor
 * @see org.springframework.beans.propertyeditors.ClassArrayEditor
 * @see org.springframework.core.io.support.ResourceArrayPropertyEditor
 */
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
    ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
    doRegisterEditor(registry, Resource.class, baseEditor);
    doRegisterEditor(registry, ContextResource.class, baseEditor);
    doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
    doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
    doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
    doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
    doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
    doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

    ClassLoader classLoader = this.resourceLoader.getClassLoader();
    doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
    doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
    doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

    if (this.resourceLoader instanceof ResourcePatternResolver) {
        doRegisterEditor(registry, Resource[].class,
                new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
    }
}

/**
 * Override default editor, if possible (since that‘s what we really mean to do here);
 * otherwise register as a custom editor.
 */
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
    if (registry instanceof PropertyEditorRegistrySupport) {
        ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
    }
    else {
        registry.registerCustomEditor(requiredType, editor);
    }
}

在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 中有这样一个方法:

/**
 * Actually register the default editors for this registry instance.
 */
private void createDefaultEditors() {
    this.defaultEditors = new HashMap<>(64);

    // Simple editors, without parameterization capabilities.
    // The JDK does not contain a default editor for any of these target types.
    this.defaultEditors.put(Charset.class, new CharsetEditor());
    this.defaultEditors.put(Class.class, new ClassEditor());
    this.defaultEditors.put(Class[].class, new ClassArrayEditor());
    this.defaultEditors.put(Currency.class, new CurrencyEditor());
    this.defaultEditors.put(File.class, new FileEditor());
    this.defaultEditors.put(InputStream.class, new InputStreamEditor());
    this.defaultEditors.put(InputSource.class, new InputSourceEditor());
    this.defaultEditors.put(Locale.class, new LocaleEditor());
    this.defaultEditors.put(Path.class, new PathEditor());
    this.defaultEditors.put(Pattern.class, new PatternEditor());
    this.defaultEditors.put(Properties.class, new PropertiesEditor());
    this.defaultEditors.put(Reader.class, new ReaderEditor());
    this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
    this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
    this.defaultEditors.put(URI.class, new URIEditor());
    this.defaultEditors.put(URL.class, new URLEditor());
    this.defaultEditors.put(UUID.class, new UUIDEditor());
    this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());

    // Default instances of collection editors.
    // Can be overridden by registering custom instances of those as custom editors.
    this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
    this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
    this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
    this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
    this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));

    // Default editors for primitive arrays.
    this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
    this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());

    // The JDK does not contain a default editor for char!
    this.defaultEditors.put(char.class, new CharacterEditor(false));
    this.defaultEditors.put(Character.class, new CharacterEditor(true));

    // Spring‘s CustomBooleanEditor accepts more flag values than the JDK‘s default editor.
    this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
    this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));

    // The JDK does not contain default editors for number wrapper types!
    // Override JDK primitive number editors with our own CustomNumberEditor.
    this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
    this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
    this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
    this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
    this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
    this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
    this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
    this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
    this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
    this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
    this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
    this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
    this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
    this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));

    // Only register config value editors if explicitly requested.
    if (this.configValueEditorsActive) {
        StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
        this.defaultEditors.put(String[].class, sae);
        this.defaultEditors.put(short[].class, sae);
        this.defaultEditors.put(int[].class, sae);
        this.defaultEditors.put(long[].class, sae);
    }
}

具体的调用方法我们就不去深究了,但是至少通过这个方法我们已经知道了在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 中并没有做过多逻辑处理。

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    return bean;
}

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

@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;

    if (System.getSecurityManager() != null &&
            (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                    bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                    bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
        acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }

    if (acc != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    }
    else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}

private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

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

4. 设置忽略依赖

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

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

5. 注册依赖

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

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

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

 

spring源码分析(二十三)beanfactory的后处理

摘要:本文结合《Spring源码深度解析》来分析Spring5.0.6版本的源代码。若有描述错误之处,欢迎指正。 目录一、激活注册的BeanFactoryPostProcessor1.BeanFactoryPostProcessor的典型应用:PropertyPlaceholderConfigurer2.使用自定义BeanFactoryPostProces... 查看详情

spring源码分析(二十四)初始化非延迟加载单例

摘要:本文结合《Spring源码深度解析》来分析Spring5.0.6版本的源代码。若有描述错误之处,欢迎指正。  完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。/***Finishtheini... 查看详情

(二十二)枚举类型基础

publicclassTest{publicstaticvoidmain(String[]args){//测试普通的枚举类型System.out.println("SPRING的值="+season.SPRING);//遍历普通枚举类新System.out.println("---遍历普通枚举类型---");for(seasonstr:season.values()){System.out.pri 查看详情

spring源码分析ioc容器初始化(总结)

...的bean,转换成我们实际所需要的真正的bean对象。总结【spring源码分析】IOC容器初始化(一):主要分析了Spring是如何解析占位符以及BeanFactory的最终实现类DefaultListableBeanFactory。【s 查看详情

abp源码分析二十:applicationservice

IApplicationService:空接口,起标识作用。所有实现了IApplicationService的类都会被自动注入到容器中。同时所有IApplicationService对象都会被注入一些拦截器(例如:auditing,UnitOfWork等)以实现AOPAbpServiceBase:抽象类,封装了对一些通用功... 查看详情

java学习笔记之二十二解析接口在java继承中的用法及实例分析

一、定义Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。 接口定... 查看详情

spring读源码系列06----容器扩展功能--上

Spring读源码系列06----容器扩展功能---上ApplicationContextClassPathXmlApplicationContext构造函数AbstractRefreshableConfigApplicationContext#setConfigLocations---设置配置文件路径AbstractApplicationContext#refresh---刷新容器Abstrac 查看详情

spring读源码系列07----容器扩展功能--中

Spring读源码系列07----容器扩展功能--中添加ApplicationContextAwareProcessor处理器initializeBean方法回顾(bean初始化过程)invokeAwareMethodsapplyBeanPostProcessorsBeforeInitializationinvokeInitMethodsapplyBeanPostProcessorsAfterIn 查看详情

spring读源码系列08----容器扩展功能--下

Spring读源码系列08----容器扩展功能--下注册BeanPostProcessorregisterBeanPostProcessorsPostProcessorRegistrationDelegate#registerBeanPostProcessors初始化消息资源initMessageSourceMessageSource在哪里被使用呢?初始化ApplicationEve 查看详情

学习二十二

五周第四次课(3月8日)8.6管道符和作业控制8.7/8.8shell变量8.9环境变量配置文件扩展bashrc和bash_profile的区别http://ask.apelearn.com/question/7719简易审计系统:http://www.68idc.cn/help/server/linux/2014042190951.html关于PROMPT_COMMAND环境变量的含义http: 查看详情

二十二macd和rsi技术分析指标

...学工程与工艺,大学沉迷日语,Python,Java和一系列数据分析软件。导致翘课严重,专业排名中下。.在大学60%的时间,都在CSDN。在之前都是去年的笔记,在今天我写了一份金融数据和量化交易文章目录6、金融数据和量化交易6.2.4... 查看详情

tableau可视化数据分析60讲(二十二)-tableau常见面试题目

...au的高级部分内容,大家可自行订阅专栏tableau可视化数据分析高级教程https://blog.csdn.net/wenyusuran/category_9596753.html面试题目什么是Tableau?Tableau是一种商业智能软件,允许任何人连接到相应的数据,然后可视化并创建交互式的可共... 查看详情

rocketmq(二十二)高级功能汇总(代码片段)

1、消息存储分布式队列因为有高可靠性的要求,所以数据要进行持久化存储。消息生成者发送消息MQ收到消息,将消息进行持久化,在存储中新增一条记录返回ACK给生产者MQpush消息给对应的消费者,然后等待消费... 查看详情

springboot入门二十二,使用validation进行参数校验

  项目基本配置参考文章SpringBoot入门一,使用myEclipse新建一个SpringBoot项目,使用myEclipse新建一个SpringBoot项目即可,此示例springboot升级为2.2.1版本。 1.pom.xml添加aop支持如果已经引用了spring-boot-starter-web,就不要需要引用spring-boot-s... 查看详情

(二十二)查询订单的详情

...有未付款的订单,点击"付款",跳转到订单的详情页面步骤分析:1.在订单列表,点击付款,/store/order?method=getById&oid=?2.在orderservlet中编写getById()接受oid调用service返回Order将order放入域中,请求转发order_info.jsp3.orderDao中通过一个订单号,... 查看详情

c#编程(二十二)----------继承的类型

继承的类型在面向对象的编程中,有两种截然不同的集成类型:实现继承和接口继承实现继承:表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数.在实现继承中,派生类型采用基类型的每个函数的实现代码,除非... 查看详情

欢迎来怼--第二十二次scrum会议

小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文小组照片 二、开会信息时间:2017/11/217:05~17:25,总计20min。地点:东北师范大学一食堂二楼雅间位置,面向日华公寓的窗口,从右到左第二个木桌相对的... 查看详情

qt开发(二十二)——qmainwindow主窗口

QT开发(二十二)——QMainWindow主窗口一、主窗口简介    应用程序中的主窗口是与用户进行长时间交互的顶层窗口,提供了应用程序的大部分功能,通常是应用程序启动后的第一个窗口,应用程序一般由一个主窗... 查看详情