zoukankan      html  css  js  c++  java
  • Bean后置处理器

    代码片段:

    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 是 ConfigurationClassEnhancer 的一个内部接口, 是给 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在MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition的时候执行过.

    所以这里, 大概率是从缓存中拿取结果, 然后进行注入操作. 事实上, 也确实如此.

    inject 最终会调用

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

    这里分两种情况进行处理, 一种是 通过字段注入, 另一种是通过方法注入.

    字段注入的方式是比较多见的. 

    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<String> 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在MergedBeanDefinitionPostProcessor#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<String> 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);
        }
    }

    这里有一个隐藏的后置处理器: SmartInstantiationAwareBeanPostProcessor

    留到下一篇看

  • 相关阅读:
    python 字典转对象实现
    漏洞复现的整理
    mlx90614红外传感器
    【小程序码】登录的技术实现案例
    Spring mvc Aop
    MSHFLEXGRID常用的属性,方法事件
    InsertAuditEntryNew
    Froggy 的 CSP-2021 S1 游记
    JOI Open 偷学记录
    生产订单工序新增、修改、删除——CO_SE_PRODORD_OPR_CREATE、CO_SE_PRODORD_OPR_CHANGE、CO_SE_PRODORD_OPR_DELETE
  • 原文地址:https://www.cnblogs.com/elvinle/p/13384328.html
Copyright © 2011-2022 走看看