Bean後置プロセッサ-I n s t a n tiationAwareBeanPostProcessor#postProcessProperties

21009 ワード

コードクリップ:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// ,  
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // ,  
       // @Autowired @Resource
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } }

同様に、デバッグによって、ここではバックグラウンドプロセッサが使用されていることを確認します.
1.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
2.CommonAnnotationBeanPostProcessor
3.AutowiredAnnotationBeanPostProcessor
 

ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor

@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
    // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
    // postProcessProperties method attempts to autowire other configuration beans.
    if (bean instanceof EnhancedConfiguration) {
        ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
    }
    return pvs;
}

ここではEnhancedConfigurationのサポートを行います.実は彼はBeanFactoryAwareインタフェースを引き継いで、何もしていません.
public interface EnhancedConfiguration extends BeanFactoryAware {}

EnhancedConfigurationはConfiguration ClassEnhancerの内部インタフェースで、spring自身の内部に使用されています.開発者はこれを使えません.必要もありません.
 

CommonAnnotationBeanPostProcessor

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // @Resource 
    //else if (field.isAnnotationPresent(Resource.class))
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
    }
    return pvs;
}

ここでは主に@Resourceへの注入
findResourceMetadataは、M e r g e d BeanDefinitionPostProcessor.postProcessMergedBeanDefinitionのときに実行する.
ここで、おおよそのレートは、キャッシュから結果を取り出す注入操作を行う.実は、確かにそうです.
 
プロジェクトは最終的に呼び出されます
org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#injectメソッド
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
        throws Throwable {

    if (this.isField) {
        Field field = (Field) this.member;
        ReflectionUtils.makeAccessible(field);
        field.set(target, getResourceToInject(target, requestingBeanName));
    }
    else {
        if (checkPropertySkipping(pvs)) {
            return;
        }
        try {
            Method method = (Method) this.member;
            ReflectionUtils.makeAccessible(method);
            method.invoke(target, getResourceToInject(target, requestingBeanName));
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
    }
}

ここでは、フィールド注入と方法注入の2つのケースに分けて処理する.
フィールド注入の方式は比較的多く見られる. 
getResourceToInject()メソッドは書き換えられたメソッドです.
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject
彼は内部クラスで書き換えられる方法だ.
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
    return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
            getResource(this, requestingBeanName));
}

デフォルトではlazy=falseなのでgetResource()メソッドを実行します
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#getResource
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
        throws NoSuchBeanDefinitionException {

    if (StringUtils.hasLength(element.mappedName)) {
        return this.jndiFactory.getBean(element.mappedName, element.lookupType);
    }
    if (this.alwaysUseJndiLookup) {
        return this.jndiFactory.getBean(element.name, element.lookupType);
    }
    if (this.resourceFactory == null) {
        throw new NoSuchBeanDefinitionException(element.lookupType,
                "No resource factory configured - specify the 'resourceFactory' property");
    }
    return autowireResource(this.resourceFactory, element, requestingBeanName);
}

設定する属性によって、異なる方法を進みます.ここでは主にautowireResourceを見ます.一般的にはこれらの属性を設定する必要はありませんから.
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
        throws NoSuchBeanDefinitionException {

    Object resource;
    Set autowiredBeanNames;
    String name = element.name;

    if (factory instanceof AutowireCapableBeanFactory) {
        AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
        DependencyDescriptor descriptor = element.getDependencyDescriptor();
        //    name  ,   name   beanName
        //  beanName  ,   type  
        //  !factory.containsBean(name) 
        if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
            autowiredBeanNames = new LinkedHashSet<>();
            // type( ) 
            resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
            if (resource == null) {
                //  resource ,  , spring ,    bean
                throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
            }
        }
        else {
            // name( ) 
            resource = beanFactory.resolveBeanByName(name, descriptor);
            autowiredBeanNames = Collections.singleton(name);
        }
    }
    else {
        resource = factory.getBean(name, element.lookupType);
        autowiredBeanNames = Collections.singleton(name);
    }

    if (factory instanceof ConfigurableBeanFactory) {
        ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
        for (String autowiredBeanName : autowiredBeanNames) {
            if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
            }
        }
    }

    return resource;
}

@Resourceは、nameとtypeを設定場合、nameを優先して依存beanを取得/作成し、nameが見つからない場合にtypeを使用する.
このコードは、サポートの根拠です.
 

AutowiredAnnotationBeanPostProcessor

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

ここでは主に@Autowiredと@Valueを注入する. findAutowiringMetadata
findAutowiringMetadataは、M e r g e d BeanDefinitionPostProcessor.postProcessMergedBeanDefinitionの場合に実行する.
ここでは、結果をキャッシュから取り出す注入操作を行う.
最終的には、このクラスのメソッドが呼び出されます.
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            //  type  
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        synchronized (this) {
            if (!this.cached) {
                if (value != null || this.required) {
                    this.cachedFieldValue = desc;
                    registerDependentBeans(beanName, autowiredBeanNames);
                    if (autowiredBeanNames.size() == 1) {
                        String autowiredBeanName = autowiredBeanNames.iterator().next();
                        if (beanFactory.containsBean(autowiredBeanName) &&
                                beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                            this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                    desc, autowiredBeanName, field.getType());
                        }
                    }
                }
                else {
                    this.cachedFieldValue = null;
                }
                this.cached = true;
            }
        }
    }
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}

 
ここには非表示のバックグラウンドプロセッサがあります:S o r t i n s t a n t i a tionAwareBeanPostProcessor
次編まで残して読む