2009-07-29 13 views
35

Al iniciar jugar un poco con la materia de proxy automático de la primavera, a menudo se encuentra con este comportamiento tal como se documenta:La localización de la causa de la primavera de "no es elegible para auto-proxy"

Las clases que implementan la interfaz BeanPostProcessor son especial, y por lo que se tratan diferente por el recipiente. Todos BeanPostProcessors y sus directamente granos de referencia se creará una instancia en el arranque, como parte de la fase especial inicio de la Application Context, entonces todos esos BeanPostProcessors serán registrados de una manera ordenada - y se aplican a todos los granos más . Desde AOP auto-proxy se implementa como un BeanPostProcessor sí mismo, no hay BeanPostProcessors o directamente granos de referencia son elegibles para auto-proxy (y por lo tanto no tendrá aspectos 'tejidas' en ellos.

Para cualquier tales frijol, debería ver un mensaje de registro Info: “ 'foo' bean no es elegible para obtener procesados ​​por todos BeanPostProcessors (por ejemplo: no elegibles para auto-proxy)”.

En otras palabras, si escribo mi propia BeanPostProcessor, y que clase de referencias directamente otros granos en el contexto, a continuación, los granos que se hace referencia no será elegible para auto-proxy, y se registra un mensaje a tal efecto.

Mi problema es que rastrear cuando dicha referencia directa es puede ser muy difícil, ya que la "referencia directa" puede ser en realidad una cadena de dependencias transitivas que acaba de tomar en la mitad de los granos en el contexto de aplicación. Todo lo que Spring le ofrece es ese mensaje de información único, y no es de mucha ayuda, más allá de decirle cuándo se ha atrapado un frijol en esta red de referencias.

El BeanPostProcessor estoy desarrollando tiene referencias directas a otros granos, pero es un conjunto muy limitado de referencias. A pesar de ello, casi todos los frijoles en mi contexto y luego se excluye de esto proxy automático, de acuerdo con los mensajes de registro, pero no puedo ver dónde que la dependencia está sucediendo.

Alguien ha encontrado una mejor forma de seguimiento de esto abajo?

+0

También puede obtener ese mensaje de información para las clases 'PersistenceExceptionTranslator'. – Raedwald

Respuesta

17

sólo para llevar un cierre a esta pregunta, el colapso de la gráfico de objeto no inicializado fue causado por el uso de BeanPostProcessor@Autowired para conseguir sus dependencias, y el mecanismo de Autowire causado efectivamente todos los demás definición de frijol a ser inicializado antes de mi BeanPostProcessor tuvo la oportunidad de tener una voz en el asunto. La solución es no utilizar el autoenvío para sus BPP.

+2

Esto no es una solución; ¿Qué debo hacer cuando necesito frijoles en mi post procesador? –

3

No estoy seguro si es de alguna ayuda, pero el Eclipse Spring IDE 's graph view parece que podría ser útil en la clasificación de las referencias de frijol ..

21

Siga esta receta:

  1. abierto BeanPostProcessorChecker en su IDE (que es una clase interna de AbstractApplicationContext)
  2. Establecer un punto de interrupción en if (logger.isInfoEnabled()) { en el método postProcessAfterInitialization
  3. ejecutar el código
  4. Cuando Llegas al punto de interrupción, busca las llamadas al getBean(String,Class<T>) en tu rastro de pila.

    Una de estas llamadas intentará crear un BeanPostProcessor. Ese frijol debería ser el culpable.

Antecedentes

Imagínese esta situación:

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

Cuando la primavera tiene que crear config (ya que es una dependencia de FooPP), tiene un problema: El contrato dice que todos BeanPostProcessor se debe aplicar a cada bean que se está creando. Pero cuando Spring necesita config, hay al menos un PP (es decir, FooPP) que no está listo para el servicio.

Esto empeora cuando se utiliza una clase @Configuration para definir este bean:

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

Cada clase de configuración es un bean. Eso significa que para construir una fábrica de beans de BadSpringConfig, la primavera tiene que aplicar el postprocesador fooPP pero con el fin de hacer eso, primero se necesita la fábrica de beans ...

En este ejemplo, es posible romper una de las dependencias cíclicas Puede hacer que FooPP implemente BeanFactoryAware para que Spring inserte el BeanFactory en el procesador de postes. De esta forma, no necesita autovinculación.

Más adelante en el código, puede pedir con pereza para el bean:

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 for LazyInit)

Para romper el ciclo entre la fábrica de beans y el post-procesador, es necesario configurar el cargo procesador en un archivo de configuración XML. Spring puede leer eso y construir todas las estructuras sin confundirse.

+0

¿esta solución sigue siendo adecuada en aplicaciones de subprocesamiento múltiple como servicios web? – hudi

+0

'LazyInit' es seguro, así que sí. –

+0

Pude usar esto para localizar este problema cuando estaba convirtiendo una aplicación de Jersey en Spring Boot. Resulta que tenía un bean llamado "conversionService", y ConfigurationPropertiesBindingPostProcessor busca un bean (opcional) con ese nombre. Dado que se trataba de un BeanPostProcessor que hacía referencia a mi bean, mis beans a los que hacía referencia mi servicio de conversión no se cableaban correctamente (por ejemplo, sus campos @Autowired no se estaban configurando). –

Cuestiones relacionadas