spring 注入接口注意事项

今天讨论的是一点注意事项,大家都知道spring 一个很大的有点就是ioc,DI,今天想着接口注入能不能在属性配置中配置接口,然后看下回报出什么错误?相关测试配置如下:

<bean id="documentManager" class="com.itheima12.spring.iocdi.document.DocumentManager">
           <!-- 
               该属性是一个接口
            -->
           <property name="document">
               <ref bean="document"/>
           </property>
   </bean>
   <bean id="document" class="com.itheima12.spring.iocdi.document.Document"></bean>
   <bean id="wordDocument" class="com.itheima12.spring.iocdi.document.WordDocument"></bean>

----------------------------------------------------------------------------

public interface Document {
    public void readDocument();
    public void writeDocument();
}
----------------------------------------------------------

public class DocumentManager {
    private Document document;
    
    
    public Document getDocument() {
        return document;
    }

    public void setDocument(Document document) {
        this.document = document;
    }

    public void readDocument(){
        this.document.readDocument();
    }
    
    public void writeDocument(){
        this.document.writeDocument();
    }
}

------------------------------------------------------------------

这里只说明下关键信息点,我们spring 读取xml配置属性创建beandefination对象,在popule  注入中,创建bean注入引用类型对象,AbstractAutowireCapableBeanFactory类中createBean,

protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        // Make sure bean class is actually resolved at this point.
        resolveBeanClass(mbd, beanName);

        // Prepare method overrides.
        try {
            mbd.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbd);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        Object beanInstance = doCreateBean(beanName, mbd, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

创建我们实体的bean,调用resolveBeforeInstantiation方法,首先判断是否是class类型,如果是则进行进一步bean解析创建,代码如下:

    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

所以我们上述配置并不会创建bean,因为在创建bean时首先判断该类是否是class类型,所以执行Object beanInstance = doCreateBean(beanName, mbd, args);方法,创建bena对象调用createBeanInstance方法,

public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides.
        if (beanDefinition.getMethodOverrides().isEmpty()) {
            Constructor<?> constructorToUse;
            synchronized (beanDefinition.constructorArgumentLock) {
                constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    final Class clazz = beanDefinition.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }

                    try {
                        if (System.getSecurityManager() != null) {
                            constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
                                public Constructor run() throws Exception {
                                    return clazz.getDeclaredConstructor((Class[]) null);
                                }
                            });
                        }
                        else {
                            constructorToUse =    clazz.getDeclaredConstructor((Class[]) null);
                        }
                        beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Exception ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            // Must generate CGLIB subclass.
            return instantiateWithMethodInjection(beanDefinition, beanName, owner);
        }
    }

在此方法中final Class clazz = beanDefinition.getBeanClass();,调试可以知道clazz对象interface com.itheima12.spring.iocdi.document.Document,然后判断是否为借口,那么此时判断为true,抛出BeanInstantiationException(clazz, "Specified class is an interface");异常,所以根据探究源码可以得出,我们在注入接口时要指向它的实现类,这点大家注意,如果配置指向实现类则ok,

<bean id="documentManager" class="com.itheima12.spring.iocdi.document.DocumentManager">
           <!-- 
               该属性是一个接口
            -->
           <property name="document">
               <ref bean="document"/>
           </property>
   </bean>
   <bean id="document" class="com.itheima12.spring.iocdi.document.wordDocument"></bean>

调试出真知,有不正确的地方请大家指出,希望大家交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值