Frage Ursache von Spring "nicht für Autoproxying geeignet"


Wenn Sie anfangen, sich mit dem Auto-Proxy-Zeug von Spring zu beschäftigen, stoßen Sie oft auf dieses Verhalten, wie es dokumentiert ist:

Klassen, die das implementieren   BeanPostProcessor Schnittstelle sind   speziell, und so werden sie behandelt   anders durch den Container. Alle   BeanPostProcessors und ihre direkt   referenzierte Beans werden instanziiert   beim Start, als Teil des speziellen   Startphase der   ApplicationContext, dann all diese   BeanPostProcessors werden registriert   in einer sortierten Weise - und angewendet auf   alle weiteren Bohnen. Seit AOP   Autoproxying wird als implementiert   BeanPostProcessor selbst, nein   BeanPostProcessors oder direkt   referenzierte Beans sind berechtigt   Autoproxying (und wird somit nicht haben   Aspekte "verwoben".

Für eine solche Bohne sollten Sie eine sehen   Info-Log-Nachricht: "Bean 'foo' ist nicht   berechtigt, von allen verarbeitet zu werden   BeanPostProcessors (zum Beispiel: nicht   geeignet für Autoproxying) ".

Mit anderen Worten, wenn ich meinen eigenen BeanPostProcessor schreibe und diese Klasse direkt auf andere Beans im Kontext verweist, sind diese referenzierten Beans nicht für die automatische Proxy-Verarbeitung geeignet, und eine Nachricht wird mit diesem Effekt protokolliert.

Mein Problem ist, dass das Aufspüren, wo diese direkte Referenz ist, sehr schwierig sein kann, da die "direkte Referenz" tatsächlich eine Kette transitiver Abhängigkeiten sein kann, die letztendlich die Hälfte der Beans im Anwendungskontext einnehmen. All Spring gibt Ihnen diese einzige Info-Nachricht, und es ist nicht wirklich hilfreich, wenn Sie nicht wissen, wann eine Bean in diesem Referenznetz gefangen wurde.

Der BeanPostProcessor, den ich entwickle, hat direkte Verweise auf andere Beans, aber es ist ein sehr begrenzter Satz von Referenzen. Trotzdem wird so ziemlich jede Bohne in meinem Kontext gemäß den Protokollnachrichten von einer automatischen Proxy-Verarbeitung ausgeschlossen, aber ich kann nicht sehen, wo diese Abhängigkeit stattfindet.

Hat jemand eine bessere Möglichkeit gefunden, dies zu verfolgen?


36
2017-07-29 17:06


Ursprung


Antworten:


Folge diesem Rezept:

  1. Öffnen BeanPostProcessorChecker in deiner IDE (es ist eine innere Klasse von AbstractApplicationContext)
  2. Setzen Sie einen Haltepunkt auf if (logger.isInfoEnabled()) { in der Methode postProcessAfterInitialization
  3. Führen Sie Ihren Code aus
  4. Wenn Sie den Haltepunkt berühren, suchen Sie nach Anrufen an getBean(String,Class<T>) in Ihrem Stack-Trace.

    Einer dieser Anrufe wird versuchen, ein BeanPostProcessor. Diese Bohne sollte der Schuldige sein.

Hintergrund

Stellen Sie sich diese Situation vor:

public class FooPP implements BeanPostProcessor {
    @Autowire
    private Config config;
}

Wenn Frühling erschaffen muss config (Da es eine Abhängigkeit von ist FooPP), es hat ein Problem: Der Vertrag sagt das alles BeanPostProcessor muss auf jede Bean angewendet werden, die gerade erstellt wird. Aber wenn der Frühling braucht config, es gibt mindestens einen PP (nämlich FooPP) die nicht bereit für den Service ist!

Dies wird schlimmer, wenn Sie eine verwenden @Configuration Klasse zum Definieren dieser Bean:

@Configuration
public class BadSpringConfig {
     @Lazy @Bean public Config config() { return new Config(); }
     @Lazy @Bean public FooPP fooPP() { return new FooPP(); }
}

Jede Konfigurationsklasse ist eine Bean. Das bedeutet, eine Bohnenfabrik zu bauen BadSpringConfig, Spring muss den Postprozessor anwenden fooPP aber um das zu tun, braucht es zuerst die Bohnenfabrik ...

In diesem Beispiel ist es möglich, eine der zyklischen Abhängigkeiten zu unterbrechen. Du kannst das schaffen FooPP implementieren BeanFactoryAware Frühlingsspritze bekommen BeanFactory in den Postprozessor. Auf diese Weise brauchen Sie kein Autowiring.

Später im Code können Sie nach der Bohne fragen:

private LazyInit<Config> helper = new LazyInit<Config>() {

    @Override
    protected InjectionHelper computeValue() {
        return beanFactory.getBean( Config.class );
    }
};

@Override
public Object postProcessBeforeInitialization( Object bean, String beanName ) throws BeansException {
     String value = helper.get().getConfig(...);
}

(Quelle für LazyInit)

Um den Zyklus zwischen der Bean-Factory und dem Postprozessor zu unterbrechen, müssen Sie den Postprozessor in einer XML-Konfigurationsdatei konfigurieren. Der Frühling kann das lesen und alle Strukturen aufbauen, ohne verwirrt zu werden.


24
2017-10-30 16:34



Um diese Frage zu klären, wurde der Kollaps des nicht initialisierten Objektgraphen durch die BeanPostProcessor verwenden @Autowired um seine Abhängigkeiten zu erhalten, und der Autowire-Mechanismus bewirkte effektiv, dass jede andere Bean-Definition vor my initialisiert wurde BeanPostProcessor bekam eine Chance, ein Mitspracherecht zu haben. Die Lösung besteht nicht darin, Autowiring für Ihre BPPs zu verwenden.


19
2017-09-06 08:09



Ich bin mir nicht sicher, ob es hilfreich ist, aber die Eclipse Frühlings-IDEist es Diagrammansicht sieht so aus, als könnte es beim Aussortieren von Bean-Referenzen hilfreich sein.


4
2017-08-02 09:46