2017-06-13 8 views
0

Ich habe ein seltsames Problem bekam (oder vielleicht nur einige Missverständnis über Spring 4.1.7):@Autowired überschreibt @Bean

Es gibt eine Komponente, nennen wir es MyComponent, dass so aussieht ...

@Component 
public class MyComponent extends BaseComponent { 
... 
} 

BaseComponent ist so etwas wie dieses ...

public class BaseComponent {  
    @Autowired 
    private HibernateTemplate hibernateTemplate; 

    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { 
     this.hibernateTemplate = hibernateTemplate; 
    } 
} 

Während die Klasse mit @Component aus historischen Gründen mit Anmerkungen versehen ist, bauteil Scannen nicht für dieses Paket aktiviert wird, so dass die Komponente nicht automatisch gefunden werden. So habe ich eine Definition in meinem @Configuration ...

@Configuration 
public class MyConfiguration { 

@Bean 
public HibernateTemplate hibernateTemplate() { ... create one ... } 


@Bean 
public HibernateTemplate hibernateTemplateSecondary() { ... create another one ... } 


@Bean 
public MyComponent myComponent() { 
    MyComponent component = new MyComponent(); 
    component.setHibernateTemplate(hibernateTemplateSecondary()); 
    return component; 
} 
} 

Leider jetzt, was passiert ist, dass myComponent zuerst richtig mit den sekundären HibernateTemplate initialisiert werden, aber danach spritzt Frühling die „normalenhibernateTemplate hinein (was falsch ist).

Ich habe versucht explizit autowire = Autowire.NO auf die @Bean Definition hinzuzufügen, auch wenn das schon der Standard ... Auch gibt es keine zwei myComponent Bohnen, es ist immer die gleiche ...

Hat jemand eine Idee, warum das passiert und wenn ja, wie kann man das verhindern? Ich dachte immer, wenn @Bean beteiligt ist, überschreibt @Autowired das nicht?

Bitte beachten Sie: Da MyComponent auch in anderen Projekten verwendet wird, kann ich es absolut nicht anfassen. Ich kann das @Autowired nicht entfernen und ich kann kein @Qualifier oder ähnliches hinzufügen, weil das viele andere Projekte brechen würde. Normalerweise funktioniert es gut, da es die "primäre" (und normalerweise nur) Datenbankverbindung verwendet. Nur in diesem Modul sollte eine andere Datenbank die primäre Datenbank sein und daher muss MyComponents angewiesen werden, die sekundäre Datenbank zu verwenden.

+2

Warum nicht einfach den '@ Autowired' entfernen? – Henry

+0

Das ist nicht möglich, da 'MyComponent' in vielen anderen Modulen verwendet wird, in denen es von Komponenten gescannt wird. Nur in diesem Modul sollte es nicht sein (da dieses Modul eine andere "primäre" Datenbank verwendet). –

+0

Um Ihr Problem zu verstehen, erste Mal HibernateTemplate-Variable in BaseComponent verdrahtet mit HibernateTemplate-Objekt von HibernateTemplateSecondary() -Methode und später die gleiche HibernateTemplate-Variable überschreiben die ursprüngliche HibernateTemplate mit der HibernateTemplate() -Methode. Ist das dein Punkt richtig? –

Antwort

1

Können Sie nicht einfach @Qualifier ("hibernateTemplateSecondary") in der BaseComponent verwenden, damit es die richtige Bean aufnehmen kann?

@Autowired 
@Qualifier("hibernateTemplateSecondary") 
private HibernateTemplate hibernateTemplate; 

Ein weiterer Ansatz ist die primäre Anmerkung zu verwenden, die nicht gut in Ihrem Fall sehen (unter Berücksichtigung, dass es Ihre Sekundär Bean)

@Bean 
@Primary 
public HibernateTemplate hibernateTemplateSecondary() { ... create another one ... } 
+0

Leider kann ich 'MyComponent' nicht berühren. Ich weiß, dass dies das Problem lösen würde, ohne Zweifel, und es wäre auch mein bevorzugter Ansatz, aber es wird in mehreren anderen Modulen verwendet (und dort wird Komponenten-Scannen verwendet). –

1

vielleicht gibt es eine bessere Lösung, aber man konnte lösen dies mit einem BeanPostProcessor wie folgt aus:

@Component 
public class MyBeanPostProcessor implements BeanPostProcessor { 

    @Autowired 
    @Qualifier("hibernateTemplateSecondary") 
    private HibernateTemplate hibernateTemplateSecondary; 

    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
    return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
    if (bean instanceof MyComponent) { 
     ((MyComponent) bean).setHibernateTemplate(hibernateTemplateSecondary); 
    } 
    return bean; 
    } 
} 

Dies wird injizieren hat die richtige Vorlage nach die Bohne gewesen Anfangs und überschreibt den falschen.

+0

Dies ist ähnlich (aber etwas besser) als die aktuelle Problemumgehung (injiziere die sekundäre Hibernate-Vorlage mit der MyComponent in alle Beans und rufe den Setter dort erneut auf). Vielen Dank. Es löst das Problem nicht selbst, aber es scheint eine vernünftige Lösung zu sein. –

+0

Ich hatte auch einen Erfolg mit einem benutzerdefinierten 'InstantiationAwareBeanPostProcessorAdapter', die' false' für 'postProcessAfterInstantiation' die' MyComponent' zurückgibt, aber das ist alles Kampfsymptome, ich weiß immer noch nicht, WARUM es überhaupt Autowires. Das sollte nicht so sein, afaik. –

Verwandte Themen