2011-02-28 10 views
6
<beans default-autowire="byType /> 

significa che tutti i campi di fagioli avranno automaticamente le dipendenze iniettate se non c'è più di 1 bean con il tipo desiderato.Can @Autowired e default-autowire coesistono?

La domanda è: come funziona quando si utilizzano le annotazioni e funziona del tutto.

mio test ha dimostrato che, anche se uso

@Resource(name="someConcreteFoo") 
private Foo foo; 

contesto cerca di autowire campo per tipo e non riesce se ci sono più implementazioni di Foo. Quindi, per quello che vedo, default-autowire non si confonde con le annotazioni. Non ho trovato nulla di specifico nella documentazione.

Per estendere la domanda: come si comporta la molla con il default-autowiring quando si utilizza solo xml. Cioè se hai <property>. L'iniezione di proprietà sovrascrive il valore predefinito (dovrebbe essere).

Posso fare più test, ma preferirei che il comportamento fosse confermato da alcune citazioni. Qualche intuizione?

+0

una nota particolarmente non è utile: in casi simili guardo il codice sorgente; ci vuole meno tempo che scrivere e pubblicare una risposta e mi fa essere sicuro di sapere esattamente come/perché. Sfortunatamente, non uso la molla, quindi non ho una risposta diretta. – bestsss

+2

@bestsss Lo faccio anche io. E anche se ho abbastanza familiarità con il codice di primavera (averlo fatto in varie occasioni), il meccanismo di autowiring è un po 'più difficile. Se avessi avuto un problema con questo, forse avrei passato alcune ore a cercare. Attualmente è fuori dalla curiosità, quindi sto solo controllando se qualcuno è già a conoscenza di questo. – Bozho

+0

* un po 'più difficile *; il mio tentativo (senza alcuna esperienza) di raggiungere un setter, sei sicuro di non chiamare da solo, esaminare lo stacktrace. Passa al codice (o alla mancanza) che lega la risorsa nominata. E i miei complimenti per averlo fatto da soli. Compro quasi esclusivamente le librerie di terze parti (quelle open source) dalla fonte. – bestsss

risposta

1

Edit:

fa l'iniezione di proprietà ignorare l'impostazione predefinita (dovrebbe essere).

Hai ragione. Se non si desidera che Spring estrae la dipendenza da un determinato campo di un bean, è possibile utilizzare l'annotazione @Qualifier per iniettare la dipendenza desiderata. Sto ancora cercando di trovare la documentazione che conferma — il più vicino ho potuto trovare è un post sul forum di primavera override default-autowire setting with an annotation?

Edit: Ecco un altro post @Resource considered only after default-autowire="byName" che descrive utilizzando una nuova InstantiationAwareBeanPostProcessor per cambiare l'ordine di cablaggio per avere @Resource on setter ha la precedenza su default-autowire.

0

Per quanto ne so, l'attributo autowire predefinito definisce la "modalità autowire" predefinita per quei bean cablati solo nella configurazione XML! Quindi l'autowiring basato sull'annotazione è indipendente da quello. @Autowired è sempre per tipo, @Resource è sempre per nome!
Vedere il suggerimento nella documentazione di riferimento di Spring 3.9.3:
"Se si intende esprimere l'iniezione guidata dall'annotazione per nome, non utilizzare principalmente @Autowired, anche se tecnicamente è in grado di fare riferimento a un nome di bean tramite @Qualifier valori, invece, usa l'annotazione JSR-250 @Resource, che è definita semanticamente per identificare un componente target specifico con il suo nome univoco, con il tipo dichiarato irrilevante per il processo di matching. "

+1

sì, ma se si usano entrambi, non funziona. Non è che mi aspetto che default-autowire funzioni dalle annotazioni, ma ignora le annotazioni e fallisce. – Bozho

+0

Significa che stai ricevendo un'eccezione usando '@Resource (name =" someConcreteFoo ") private Foo foo;' con 'default-autowire =" byType "' e con 'default-autowire =" byName "' l'eccezione non si verifica ? Questo sarebbe un bug in primavera presumo. – Robin

+0

con qualsiasi valore predefinito-autowire, non solo byType. Il punto è: non puoi avere il valore predefinito-autowire se vuoi usare le annotazioni. Volevo essere sicuro che questo sia il caso – Bozho

3

Ho avuto una fitta veloce nel debug di questo problema, e penso che questo potrebbe essere un bug in primavera. A mio parere, il problema deriva da seguente codice nel AbstractAutowireCapableBeanFactory

/** 
* Populate the bean instance in the given BeanWrapper with the property values 
* from the bean definition. 
* @param beanName the name of the bean 
* @param mbd the bean definition for the bean 
* @param bw BeanWrapper with bean instance 
*/ 
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) { 
    PropertyValues pvs = mbd.getPropertyValues(); 

    if (bw == null) { 
     if (!pvs.isEmpty()) { 
      throw new BeanCreationException(
        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); 
     } 
     else { 
      // Skip property population phase for null instance. 
      return; 
     } 
    } 

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the 
    // state of the bean before properties are set. This can be used, for example, 
    // to support styles of field injection. 
    boolean continueWithPropertyPopulation = true; 

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 
     for (BeanPostProcessor bp : getBeanPostProcessors()) { 
      if (bp instanceof InstantiationAwareBeanPostProcessor) { 
       InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 
       if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 
        continueWithPropertyPopulation = false; 
        break; 
       } 
      } 
     } 
    } 

    if (!continueWithPropertyPopulation) { 
     return; 
    } 

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || 
      mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 
     MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 

     // Add property values based on autowire by name if applicable. 
     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 
      autowireByName(beanName, mbd, bw, newPvs); 
     } 

     // Add property values based on autowire by type if applicable. 
     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 
      autowireByType(beanName, mbd, bw, newPvs); 
     } 

     pvs = newPvs; 
    } 

    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); 

    if (hasInstAwareBpps || needsDepCheck) { 
     PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw); 
     if (hasInstAwareBpps) { 
      for (BeanPostProcessor bp : getBeanPostProcessors()) { 
       if (bp instanceof InstantiationAwareBeanPostProcessor) { 
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 
        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 
        if (pvs == null) { 
         return; 
        } 
       } 
      } 
     } 
     if (needsDepCheck) { 
      checkDependencies(beanName, mbd, filteredPds, pvs); 
     } 
    } 

    applyPropertyValues(beanName, mbd, bw, pvs); 
} 

Personalmente penso che l'ordine di applicare l'autowiring e InstantiationAwareBeanPostProcessor è sbagliato, come l'annotazione @Resource verrebbe applicata solo nei postProcessPropertyValues, così dopo l'autowiring (a partire da quel momento il autowiring ha già fallito).

Ora non so se ci sarebbe un impatto nel cambiare l'ordine delle invocazioni, in modo che le annotazioni @Resource siano risolte prima dell'autowiring, ma questo potrebbe essere un qualcosa da sollevare come bug/correzione (ho usato il seguente modo di caricare mio contesto applicazione di test per risolvere questo problema):

ApplicationContext ctx = new ClassPathXmlApplicationContext("test/appctx.xml") { 
     protected org.springframework.beans.factory.support.DefaultListableBeanFactory createBeanFactory() { 
      return new DefaultListableBeanFactory(getInternalParentBeanFactory()) { 
       protected void populateBean(String beanName, org.springframework.beans.factory.support.AbstractBeanDefinition mbd, org.springframework.beans.BeanWrapper bw) { 
        PropertyValues pvs = mbd.getPropertyValues(); 

        if (bw == null) { 
         if (!pvs.isEmpty()) { 
          throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); 
         } 
         else { 
          // Skip property population phase for null instance. 
          return; 
         } 
        } 

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the 
        // state of the bean before properties are set. This can be used, for example, 
        // to support styles of field injection. 
        boolean continueWithPropertyPopulation = true; 

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 
         for (BeanPostProcessor bp : getBeanPostProcessors()) { 
          if (bp instanceof InstantiationAwareBeanPostProcessor) { 
           InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 
           if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 
            continueWithPropertyPopulation = false; 
            break; 
           } 
          } 
         } 
        } 

        if (!continueWithPropertyPopulation) { 
         return; 
        } 

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); 

        if (hasInstAwareBpps || needsDepCheck) { 
         PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw); 
         if (hasInstAwareBpps) { 
          for (BeanPostProcessor bp : getBeanPostProcessors()) { 
           if (bp instanceof InstantiationAwareBeanPostProcessor) { 
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 
            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 
            if (pvs == null) { 
             return; 
            } 
           } 
          } 
         } 
         if (needsDepCheck) { 
          checkDependencies(beanName, mbd, filteredPds, pvs); 
         } 
        } 

        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || 
          mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 
         MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 

         // Add property values based on autowire by name if applicable. 
         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 
          autowireByName(beanName, mbd, bw, newPvs); 
         } 

         // Add property values based on autowire by type if applicable. 
         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 
          autowireByType(beanName, mbd, bw, newPvs); 
         } 

         pvs = newPvs; 
        } 

        applyPropertyValues(beanName, mbd, bw, pvs); 
       } 
      }; 
     } 
    }; 

Speranza che aiuta

Problemi correlati