2013-02-18 15 views
8

Sto osservando un comportamento strano, speravo che qualcuno qui potesse far luce sul problema.Spring JavaConfig e CustomScopeConfigurer issue

Vorrei iniziare descrivendo il mio setup. In primo luogo, un semplice oggetto di dati

public class Apple { 
    private String name; 
    public Apple withName(String name) { 
     this.name = name; 
     return this; 
    } 
    public String getName() { 
     return name; 
    } 
} 

E una classe di test ..

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes={TestConfig.class}) 
public class AppleTest { 
    @Autowired private Apple apples; 

    @Test 
    public void simpleTest() { 
     System.out.println("OBJ: "+apples); 
    } 
} 

La configurazione è la seguente

@Configuration 
public interface ConfigInterface { 
    public Apple getApple(); 
} 

Con una classe che implementa

@Configuration 
@Import(AbstractTestConfig.class) 
public class TestConfig implements ConfigInterface { 
    public Apple getApple() { 
     return new Apple().withName("Granny apples"); 
    } 
} 

Con la dipendenza di configurazione ...

@Configuration 
public class AbstractTestConfig { 
    @Autowired ConfigInterface conf; 

    @Bean Apple myTestApple() { 
     return conf.getApple(); 
    } 
} 

Tutto questo funziona alla grande. Corro il test, vedo l'output che mi aspetto. Ma poi lancio una chiave nel volante e modifico AbstractTestConfig in modo che appaia come segue.

@Configuration 
public class AbstractTestConfig { 
    @Autowired ConfigInterface conf; 

    @Bean Apple myTestApple() { 
     return conf.getApple(); 
    } 

    // NEW CODE 
    @Bean CustomScopeConfigurer scopeConfigurer() { 
     return new CustomScopeConfigurer(); 
    } 
} 

E all'improvviso l'@Autowired oggetto conf è nullo quando è necessario costruire il fagiolo Apple.

Ancora più strano, se sposto il bean CustomScopeConfigurer nella classe TestConfig, allora funziona.

C'è qualcosa che non so riguardo gli ambiti o l'oggetto CustomScopeConfigurer in particolare?

risposta

16

copiato da primavera @Bean javadoc:

BeanFactoryPostProcessor-ritorno metodi @Bean

Particolare attenzione devono essere prese per i metodi che restituiscono @Bean Primavera BeanFactoryPostProcessor tipi (BFPP). Poiché gli oggetti BFPP devono essere istanziati molto presto nel ciclo di vita del contenitore, possono interferire con l'elaborazione di annotazioni come @Autowired, @Value e @PostConstruct all'interno delle classi @Configuration. Per evitare questi problemi del ciclo di vita, contrassegnare i metodi BFPP-return @Bean come statici. Ad esempio:

@Bean 
public static PropertyPlaceholderConfigurer ppc() { 
    // instantiate, configure and return ppc ... 
} 

Marcando questo metodo statico, può essere richiamato senza causare istanziazione della sua dichiarare @Configuration classe, evitando così i conflitti ciclo di vita summenzionati. Si noti tuttavia che i metodi statici @Bean non saranno migliorati per la semina degli ambiti e AOP come menzionato sopra. Questo funziona nei casi BFPP, in quanto in genere non fanno riferimento ad altri metodi @Bean. Come promemoria, verrà emesso un messaggio di log a livello WARN per tutti i metodi @Bean non statici con un tipo restituito assegnabile a BeanFactoryPostProcessor.

0

Dopo aver esaminato attentamente l'output di log primavera, sono venuto su questo piccolo salvatore:

[junit] 1141 [main] WARN org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method AbstractTestConfig.scopeConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details 

Io non capisco perché avere come statica fa la differenza però.

Problemi correlati