Nota: Esto pretende ser una respuesta canónica para un problema común.
Tengo una @Serviceclase Spring ( MileageFeeCalculator) que tiene un @Autowiredcampo ( rateService), pero el campo es nullcuando trato de usarlo. Los registros muestran que tanto el MileageFeeCalculatorbean como el MileageRateServicebean se están creando, pero recibo un NullPointerExceptionmensaje cada vez que intento llamar al mileageChargemétodo en mi bean de servicio. ¿Por qué no Spring autowiring el campo?
Clase de controlador:
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator();
return calc.mileageCharge(miles);
}
}
Clase de servicio:
@Service
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService; // <--- should be autowired, is null
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- throws NPE
}
}
Service bean que debe conectarse automáticamente MileageFeeCalculatorpero no lo es:
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
Cuando intento GET /mileage/3, obtengo esta excepción:
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...

Fse llama a bean dentro del constructor de otro beanS. En este caso, pase el bean requeridoFcomo parámetro al otroSconstructor de beans y anote el constructor deSwith@Autowire. Recuerde anotar la clase del primer beanFcon@Component.Respuestas:
El campo anotado
@Autowiredsenulldebe a que Spring no sabe acerca de la copia de laMileageFeeCalculatorque creónewy no sabía cómo conectarla automáticamente.El contenedor Spring Inversion of Control (IoC) tiene tres componentes lógicos principales: un registro (llamado
ApplicationContext) de componentes (beans) que están disponibles para ser utilizados por la aplicación, un sistema configurador que inyecta las dependencias de los objetos haciendo coincidir los dependencias con beans en el contexto, y un solucionador de dependencias que puede ver una configuración de muchos beans diferentes y determinar cómo instanciarlos y configurarlos en el orden necesario.El contenedor de IoC no es mágico, y no tiene forma de conocer los objetos de Java a menos que de alguna manera le informe de ellos. Cuando llama
new, la JVM crea una copia del nuevo objeto y se lo entrega directamente; nunca pasa por el proceso de configuración. Hay tres formas de configurar los beans.He publicado todo este código, usando Spring Boot para el lanzamiento, en este proyecto de GitHub ; puede ver un proyecto en ejecución completo para cada enfoque para ver todo lo que necesita para que funcione. Etiqueta con el
NullPointerException:nonworkingInyecta tus frijoles
La opción más preferible es dejar que Spring conecte automáticamente todos sus frijoles; esto requiere la menor cantidad de código y es el más fácil de mantener. Para hacer que el cableado automático funcione como usted desea, también realice el cableado automático de
MileageFeeCalculatoresta manera:Si necesita crear una nueva instancia de su objeto de servicio para diferentes solicitudes, aún puede usar la inyección usando los ámbitos de Spring Bean .
Etiqueta que funciona inyectando el
@MileageFeeCalculatorobjeto de servicio:working-inject-beanUse @Configurable
Si realmente necesita objetos creados con
newautoconexión, puede usar la@Configurableanotación Spring junto con el tejido de tiempo de compilación AspectJ para inyectar sus objetos. Este enfoque inserta código en el constructor de su objeto que alerta a Spring de que está siendo creado para que Spring pueda configurar la nueva instancia. Esto requiere un poco de configuración en su compilación (como compilar conajc) y activar los controladores de configuración de tiempo de ejecución de Spring (@EnableSpringConfiguredcon la sintaxis JavaConfig). Este enfoque es utilizado por el sistema Roo Active Record para permitir que lasnewinstancias de sus entidades obtengan la información de persistencia necesaria inyectada.Etiqueta que funciona mediante el uso
@Configurableen el objeto de servicio:working-configurableBúsqueda manual de frijoles: no recomendado
Este enfoque es adecuado solo para interactuar con código heredado en situaciones especiales. Casi siempre es preferible crear una clase de adaptador singleton que Spring pueda autoalambrar y que el código heredado pueda llamar, pero es posible solicitar directamente un bean en el contexto de la aplicación Spring.
Para hacer esto, necesita una clase a la que Spring pueda dar una referencia al
ApplicationContextobjeto:Luego, su código heredado puede llamar
getContext()y recuperar los beans que necesita:Etiqueta que funciona buscando manualmente el objeto de servicio en el contexto Spring:
working-manual-lookupfuente
@Configurationbean, donde se anota el método para hacer una instancia de una clase de bean particular@Bean.@Beanmétodos cuando usas Spring Proxy AOP?@Autowired MileageFeeCalculator calc. ¿Alguna idea?ApplicationContext. Algunos usuarios (para los cuales he cerrado como duplicados) no entienden esto.Si no está codificando una aplicación web, asegúrese de que su clase en la que se realiza @Autowiring sea un bean de primavera. Por lo general, el contenedor de primavera no se dará cuenta de la clase que podríamos considerar un grano de primavera. Tenemos que decirle al contenedor Spring acerca de nuestras clases de primavera.
Esto se puede lograr configurando en appln-contxt o la mejor manera es anotar la clase como @Component y no cree la clase anotada con un nuevo operador. Asegúrese de obtenerlo de Appln-context como se muestra a continuación.
fuente
En realidad, debe usar Objetos administrados por JVM u Objeto administrado por Spring para invocar métodos. a partir de su código anterior en su clase de controlador, está creando un nuevo objeto para llamar a su clase de servicio que tiene un objeto con cableado automático.
entonces no funcionará de esa manera.
La solución hace que este MileageFeeCalculator sea un objeto con cableado automático en el Controlador mismo.
Cambie su clase de controlador como a continuación.
fuente
Una vez me encontré con el mismo problema cuando no estaba acostumbrado
the life in the IoC world. El@Autowiredcampo de uno de mis beans es nulo en tiempo de ejecución.La causa raíz es que, en lugar de usar el bean creado automáticamente mantenido por el contenedor Spring IoC (cuyo
@Autowiredcampo seindeedinyectó correctamente), soynewingmi propia instancia de ese tipo de bean y lo uso. Por supuesto, este@Autowiredcampo es nulo porque Spring no tiene oportunidad de inyectarlo.fuente
Su problema es nuevo (creación de objetos en estilo java)
Con la anotación
@Service,@Component,@Configurationhabas se crean en elcontexto de la aplicación de la primavera cuando se inicia el servidor. Pero cuando creamos objetos usando un nuevo operador, el objeto no se registra en el contexto de la aplicación que ya está creado. Por ejemplo, la clase Employee.java que he usado.
Mira esto:
fuente
Soy nuevo en Spring, pero descubrí esta solución de trabajo. Por favor dime si es una forma despreciable.
Hago Spring inject
applicationContexten este bean:Puede poner este código también en la clase de aplicación principal si lo desea.
Otras clases pueden usarlo así:
De esta forma, cualquier objeto de la aplicación puede obtener cualquier bean (también se puede identificar
new) y de forma estática .fuente
Parece ser un caso raro, pero esto es lo que me pasó:
Usamos en
@Injectlugar de@Autowiredcuál es el estándar Java soportado por Spring. Todos los lugares funcionaron bien y los frijoles se inyectaron correctamente, en lugar de un solo lugar. La inyección de frijol parece igual¡Por fin descubrimos que el error fue que nosotros (en realidad, la función de autocompletar Eclipse) importamos en
com.opensymphony.xwork2.Injectlugar dejavax.inject.Inject!Entonces, para resumir, asegúrese de que sus anotaciones (
@Autowired,@Inject,@Service, ...) tienen paquetes correctos!fuente
Creo que te has perdido para indicarle a Spring que escanee las clases con anotaciones.
Puede usar
@ComponentScan("packageToScan")en la clase de configuración de su aplicación Spring para indicarle a Spring que escanee.@Service, @Componentlas anotaciones etc. agregan meta descripción.Spring solo inyecta instancias de esas clases que se crean como bean o se marcan con anotaciones.
Las clases marcadas con anotación deben identificarse por resorte antes de inyectar,
@ComponentScaninstruir la búsqueda de primavera para las clases marcadas con anotación. Cuando Spring lo encuentra@Autowired, busca el bean relacionado e inyecta la instancia requerida.Agregando solo anotaciones, no repara ni facilita la inyección de dependencia, Spring necesita saber dónde buscar.
fuente
<context:component-scan base-package="com.mypackage"/>a mibeans.xmlarchivoSi esto sucede en una clase de prueba, asegúrese de no haber olvidado anotar la clase.
Por ejemplo, en Spring Boot :
Transcurre algún tiempo ...
Spring Boot continúa evolucionando . Ya no es necesario usarlo
@RunWithsi usa la versión correcta de JUnit .Para
@SpringBootTesttrabajar de forma independiente, debe usar@Testdesde JUnit5 en lugar de JUnit4 .Si se consigue este mal configuración de sus pruebas se compilan, pero
@Autowiredy@Valuecampos (por ejemplo) seránnull. Dado que Spring Boot funciona por arte de magia, es posible que tenga pocas vías para depurar directamente este error.fuente
@Valueserá nulo cuando se use constaticcampos.Otra solución sería poner call:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)al constructor MileageFeeCalculator así:
fuente
ACTUALIZACIÓN: las personas realmente inteligentes se apresuraron a señalar esta respuesta, que explica la rareza, que se describe a continuación
RESPUESTA ORIGINAL:
No sé si ayuda a alguien, pero me quedé atrapado con el mismo problema incluso mientras hacía las cosas aparentemente bien. En mi método Main, tengo un código como este:
y en un
token.xmlarchivo he tenido una líneaMe di cuenta de que el package.path ya no existe, por lo que acabo de dejar la línea para siempre.
Y después de eso, NPE comenzó a llegar. En un
pep-config.xmlsolo tenía 2 frijoles:y la clase SomeAbac tiene una propiedad declarada como
por alguna razón desconocida, la configuración es nula en init (), cuando el
<context:component-scan/>elemento no está presente en absoluto, pero cuando está presente y tiene algunos bs como basePackage, todo funciona bien. Esta línea ahora se ve así:y funciona. Puede ser que alguien pueda dar una explicación, pero para mí es suficiente en este momento)
fuente
<context:component-scan/>implícitamente habilita lo<context:annotation-config/>necesario para@Autowiredque funcione.Este es el culpable de dar NullPointerException
MileageFeeCalculator calc = new MileageFeeCalculator();Estamos usando Spring, no es necesario crear objetos manualmente. La creación de objetos será atendida por el contenedor IoC.fuente
También puede solucionar este problema utilizando la anotación @Service en la clase de servicio y pasando la clase de bean A requerida como parámetro al otro constructor de clase B de beans y anote el constructor de la clase B con @Autowired. Fragmento de muestra aquí:
fuente
Lo que no se ha mencionado aquí se describe en este artículo en el párrafo "Orden de ejecución".
Después de "aprender" que tenía que anotar una clase con @Component o los derivados @Service o @Repository (supongo que hay más), para conectar automáticamente otros componentes dentro de ellos, me sorprendió que estos otros componentes aún fueran nulos dentro del constructor del componente padre.
El uso de @PostConstruct resuelve que:
y:
fuente
Esto solo es válido en caso de prueba unitaria.
Mi clase de servicio tenía una anotación de servicio y era
@autowiredotra clase de componente. Cuando probé, la clase de componente se estaba volviendo nula. Porque para la clase de servicio estaba creando el objeto usandonewSi está escribiendo una prueba unitaria, asegúrese de no crear objetos utilizando
new object(). Utilice en su lugar injectMock.Esto solucionó mi problema. Aquí hay un enlace útil
fuente
También tenga en cuenta que si, por cualquier razón, realiza un método en un
@Serviceasfinal, los beans con conexión automática a los que accederá siempre seránnull.fuente
En palabras simples, existen principalmente dos razones para que un
@Autowiredcampo seanullTu clase no es un frijol de primavera.
El campo no es un frijol.
fuente
No está completamente relacionado con la pregunta, pero si la inyección de campo es nula, la inyección basada en el constructor seguirá funcionando bien.
fuente