Saltar al contenido

¿Por qué mi campo Spring @Autowired null?

Luego de consultar con expertos en el tema, programadores de deferentes áreas y maestros dimos con la respuesta al dilema y la dejamos plasmada en esta publicación.

Solución:

El campo anotado @Autowired es null porque Spring no conoce la copia de MileageFeeCalculator que creaste con new y no sabía conectarlo 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 en ellos haciendo coincidir las dependencias con beans en el contexto, y un solucionador de dependencias que puede ver una configuración de muchos beans 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 Java a menos que usted le informe de ellos de alguna manera. Cuando usted 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 sus beans.

He publicado todo este código, usando Spring Boot para iniciar, 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 permitir que Spring conecte automáticamente todos sus beans; esto requiere la menor cantidad de código y es el más fácil de mantener. Para que el cableado automático funcione como desea, también conecte automáticamente el MileageFeeCalculator como esto:

@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 utilizando los ámbitos de frijol de Spring.

Etiqueta que funciona inyectando el @MileageFeeCalculator objeto de servicio: working-inject-bean

Utilice @Configurable

Si realmente necesita objetos creados con new para conectarse automáticamente, puede usar Spring @Configurable anotación junto con el tejido en tiempo de compilación de AspectJ para inyectar sus objetos. Este enfoque inserta código en el constructor de su objeto que alerta a Spring de que se está creando para que Spring pueda configurar la nueva instancia. Esto requiere un poco de configuración en su compilación (como compilar con ajc) y activando los controladores de configuración en tiempo de ejecución de Spring (@EnableSpringConfigured con la sintaxis JavaConfig). Este enfoque es utilizado por el sistema Roo Active Record para permitir new instancias de sus entidades para obtener 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 con @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 conectar automáticamente y que el código heredado pueda llamar, pero es posible solicitar directamente un bean al 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;
    

Entonces su código heredado puede llamar getContext() y recupere los frijoles 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 de Spring: working-manual-lookup

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 conocerá la clase que podríamos considerar como un frijol de primavera. Tenemos que decirle al contenedor Spring sobre nuestras clases de primavera.

Esto se puede lograr configurando en appln-contxt o la mejor manera es anotar la clase como @Componente y no cree la clase anotada con el operador nuevo. Asegúrese de obtenerlo de Appln-context como se muestra a continuación.

@Component
public class MyDemo 


    @Autowired
    private MyService  myService; 

    /**
     * @param args
     */
    public static void main(String[] args) 
        // TODO Auto-generated method stub
            System.out.println("test");
            ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
            System.out.println("ctx>>"+ctx);

            Customer c1=null;
            MyDemo myDemo=ctx.getBean(MyDemo.class);
            System.out.println(myDemo);
            myDemo.callService(ctx);


    

    public void callService(ApplicationContext ctx) 
        // TODO Auto-generated method stub
        System.out.println("---callService---");
        System.out.println(myService);
        myService.callMydao();

    


En realidad, debe usar Objetos administrados por JVM o Objetos administrados por Spring para invocar métodos. desde 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 cableado automáticamente.

MileageFeeCalculator calc = new MileageFeeCalculator();

por lo que no funcionará de esa manera.

La solución hace que este MileageFeeCalculator sea un objeto cableado automáticamente en el propio Controller.

Cambie su clase de controlador como se muestra a continuación.

@Controller
public class MileageFeeController 

    @Autowired
    MileageFeeCalculator calc;  

    @RequestMapping("/mileage/miles")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) 
        return calc.mileageCharge(miles);
    

Reseñas y puntuaciones

Si tienes algún reparo y disposición de prosperar nuestro artículo te proponemos realizar una glosa y con deseo lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *