Question

Lorsque vous commencez à bricoler avec les éléments du proxy automatique de Spring, vous rencontrez souvent ce problème tel que documenté:

  

Les classes qui implémentent le   Interface BeanPostProcessor sont   spécial, et donc ils sont traités   différemment par le conteneur. Tout   BeanPostProcessors et leurs directement   les haricots référencés seront instanciés   au démarrage, dans le cadre de la spéciale   phase de démarrage du   ApplicationContext, puis tous ceux   BeanPostProcessors sera enregistré   de manière triée - et appliquée à   tous les autres haricots. Depuis AOP   l'auto-proxy est implémenté en tant que   BeanPostProcessor lui-même, non   BeanPostProcessors ou directement   les haricots référencés sont éligibles pour   l'auto-proxy (et n'aura donc pas   aspects 'tissés' en eux.

     

Pour un tel haricot, vous devriez voir un   message du journal d’information: «Le haricot 'foo' n’est pas   éligible pour être traité par tous   BeanPostProcessors (par exemple: not   éligible à l'auto-proxy) ".

En d'autres termes, si j'écris mon propre BeanPostProcessor et que cette classe référence directement d'autres beans dans le contexte, ces beans référencés ne seront pas éligibles pour le proxy automatique et un message sera consigné à cet effet.

Mon problème est qu'il peut être très difficile de localiser cette référence directe, car la "référence directe" peut en fait être une chaîne de dépendances transitives qui finit par englober la moitié des fèves dans le contexte de l'application. Tout ce que Spring vous envoie, c’est ce message d’information unique, qui ne vous aidera pas beaucoup, si ce n’est à vous dire qu’un haricot est pris dans ce réseau de références.

Le BeanPostProcessor que je développe contient des références directes à d'autres beans, mais il s'agit d'un ensemble de références très limité. Malgré cela, pratiquement tous les haricots de mon contexte sont exclus de l'auto-proxy, selon les messages du journal, mais je ne vois pas où cette dépendance se produit.

Quelqu'un a-t-il trouvé un meilleur moyen de localiser cela?

Était-ce utile?

La solution 2

Juste pour mettre un terme à cette question, l’effondrement du graphe d’objet non initialisé a été provoqué par le BeanPostProcessor qui utilise @Autowired pour obtenir ses dépendances et le mécanisme autowire. a effectivement provoqué l'initialisation de toutes les autres définitions de beans avant que mon BeanPostProcessor n'ait eu la possibilité de s'exprimer. La solution consiste à ne pas utiliser le câblage automatique pour vos BPP.

Autres conseils

Suivez cette recette:

  1. Ouvrez BeanPostProcessorChecker dans votre IDE (c'est une classe interne de AbstractApplicationContext )
  2. Définissez un point d'arrêt sur if (logger.isInfoEnabled ()) { dans la méthode postProcessAfterInitialization
  3. Exécutez votre code
  4. Lorsque vous atteignez le point d'arrêt, recherchez les appels à getBean (String, Class < T >) dans le suivi de votre pile.

    L'un de ces appels tentera de créer un BeanPostProcessor . Ce haricot devrait être le coupable.

Arrière-plan

Imaginez cette situation:

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

Lorsque Spring doit créer config (puisqu'il s'agit d'une dépendance de FooPP ), il existe un problème: le contrat indique que tous BeanPostProcessor doit être appliqué à chaque haricot en cours de création. Mais lorsque Spring a besoin de config , il existe au moins un PP (à savoir FooPP ) qui n'est pas prêt pour le service!

Cela empire lorsque vous utilisez une classe @Configuration pour définir ce bean:

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

Chaque classe de configuration est un bean. Cela signifie que pour construire une fabrique de beans à partir de BadSpringConfig , Spring doit appliquer le post-processeur fooPP , mais pour cela, il a d'abord besoin de la fabrique de beans ...

Dans cet exemple, il est possible de rompre l'une des dépendances cycliques. Vous pouvez faire en sorte que FooPP implémente BeanFactoryAware pour que Spring injecte BeanFactory dans le post-processeur. De cette façon, vous n'avez pas besoin du câblage automatique.

Plus tard dans le code, vous pourrez demander paresseusement le haricot:

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(...);
}

( source de LazyInit )

Pour rompre le cycle entre la fabrique de beans et le post-processeur, vous devez configurer le post-processeur dans un fichier de configuration XML. Spring peut lire cela et construire toutes les structures sans être dérouté.

Je ne sais pas si cela peut vous aider, mais les Spring IDE d'Eclipse La vue de graphe semble pouvoir être utile pour trier les références aux beans ..

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top