El campo anotado @Autowired
se null
debe a que Spring no sabe acerca de la copia de la MileageFeeCalculator
que creó new
y 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
:nonworking
Inyecta 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 MileageFeeCalculator
esta manera:
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
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 @MileageFeeCalculator
objeto de servicio:working-inject-bean
Use @Configurable
Si realmente necesita objetos creados con new
autoconexión, puede usar la @Configurable
anotació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 con ajc
) y activar los controladores de configuración de tiempo de ejecución de Spring ( @EnableSpringConfigured
con la sintaxis JavaConfig). Este enfoque es utilizado por el sistema Roo Active Record para permitir que las new
instancias de sus entidades obtengan la información de persistencia necesaria inyectada.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Etiqueta que funciona mediante el uso @Configurable
en el objeto de servicio:working-configurable
Bú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 ApplicationContext
objeto:
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
Luego, su código heredado puede llamar getContext()
y recuperar los beans que necesita:
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}
Etiqueta que funciona buscando manualmente el objeto de servicio en el contexto Spring: working-manual-lookup
F
se llama a bean dentro del constructor de otro beanS
. En este caso, pase el bean requeridoF
como parámetro al otroS
constructor de beans y anote el constructor deS
with@Autowire
. Recuerde anotar la clase del primer beanF
con@Component
.