757 votes

Pourquoi mon domaine @Autowired de printemps a la valeur null ?

Note: Ceci est destiné à être une réponse canonique pour un problème commun.

J'ai un Ressort @Service de la classe (MileageFeeCalculator) qui a un @Autowired champ (rateService), mais le champ est null quand j'essaie de l'utiliser. Les logs montrent que les deux MileageFeeCalculator haricot et l' MileageRateService haricot sont en cours de création, mais je reçois NullPointerException chaque fois que j'essaie d'appeler l' mileageCharge méthode sur mon service bean. Pourquoi n'est-ce pas le Printemps permettra à l'autowiring le terrain?

Contrôleur de classe:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = new MileageFeeCalculator();
        return calc.mileageCharge(miles);
    }
}

Classe de Service:

@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 qui devrait être autocâblés en MileageFeeCalculator mais n'est-ce pas:

@Service
public class MileageRateService {
    public float ratePerMile() {
        return 0.565f;
    }
}

Lorsque j'essaie d' GET /mileage/3, j'obtiens cette exception:

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)
    ...

775voto

chrylis Points 22655

Le domaine annoté @Autowired est null parce que le Printemps ne sais pas à propos de la copie d' MileageFeeCalculator que vous avez créé avec new et je ne savais pas à autowire.

Le Printemps de l'Inversion de Contrôle (IoC) contenant les trois principaux composants logiques: un registre (appelé l' ApplicationContext) des composants (haricots) qui sont disponibles pour être utilisés par l'application, configurer un système qui injecte des objets dépendances par correspondance de toutes les dépendances avec des haricots dans le contexte, et une dépendance solveur qui peut regarder une configuration de nombreux types de haricots et de déterminer comment instancier et de les configurer dans l'ordre nécessaire.

Le conteneur IoC n'est pas de la magie, et il n'a aucun moyen de savoir au sujet des objets Java, à moins que vous en quelque sorte l'en informer. Lorsque vous appelez new, la JVM instancie une copie de l'objet nouveau et les mains directement à vous, il ne va jamais à travers le processus de configuration. Il y a trois façons que vous pouvez obtenir vos haricots configuré.

J'ai posté tout ce code, à l'aide de Printemps de Démarrage pour lancer, à ce projet GitHub; vous pouvez envisager un projet en cours d'exécution pour chaque approche pour voir tout ce dont vous avez besoin pour le faire fonctionner. La balise avec l' NullPointerException: nonworking

Injecter des haricots

Le plus préférable option est de laisser le Printemps autowire tous vos haricots; ce qui nécessite le moins de code et est le plus facile à gérer. Pour rendre le travail permettra à l'autowiring comme tu le voulais, aussi autowire l' MileageFeeCalculator comme ceci:

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

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

Si vous avez besoin de créer une nouvelle instance de l'objet de service pour des demandes différentes, vous pouvez toujours utiliser l'injection en utilisant le Printemps bean étendues.

Balise qui fonctionne par l'injection de la @MileageFeeCalculator service objet: working-inject-bean

Utiliser @Configurable

Si vous avez vraiment besoin des objets créés à l' new à autocâblés, vous pouvez utiliser le Printemps @Configurable d'annotation avec AspectJ au moment de la compilation de tissage à injecter de vos objets. Cette approche insère le code dans votre constructeur de l'objet que les alertes de Printemps qu'il a été créé de sorte que le Ressort peut configurer la nouvelle instance. Cela nécessite un peu de configuration dans votre construction (comme par exemple la compilation avec ajc) et de tournage sur le Printemps de la configuration de l'exécution des gestionnaires d' (@EnableSpringConfigured avec le JavaConfig syntaxe). Cette approche est utilisée par le Roo Active système d'Enregistrement pour permettre l' new instances de votre entités pour obtenir les informations persistance injecté.

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}

Balise qui fonctionne en utilisant de l' @Configurable sur le service de l'objet: working-configurable

Manuel de haricot de recherche: non recommandé

Cette approche est adaptée uniquement pour l'interfaçage avec le code existant dans des situations particulières. Il est presque toujours préférable de créer un singleton adaptateur classe que le Printemps peut autowire et le code héritage pouvez l'appeler, mais il est possible de demander directement au Printemps contexte de l'application pour un haricot.

Pour ce faire, vous avez besoin d'une classe à laquelle Printemps peut donner une référence à l' ApplicationContext objet:

@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;
    }
}

Puis votre code hérité peut appeler getContext() et de récupérer les haricots elle a besoin:

@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);
    }
}

Balise qui fonctionne manuellement en recherchant l'objet de service au Printemps contexte: working-manual-lookup

72voto

Si u ne sont pas de codage d'une application web, assurez-vous que votre classe dans laquelle @permettra à l'autowiring est fait est un ressort de haricot. Généralement au printemps conteneur ne sera pas conscient de la classe, que l'on pourrait penser, comme un ressort de haricot. Nous avons à dire au Printemps conteneur sur notre printemps classes.

Ceci peut être réalisé ma configuration dans appln-contxt ou la meilleure façon est d'annoter la classe comme @Composant et merci de ne pas créer la classe annotée à l'aide de l'opérateur new. Assurez-vous que u l'obtenir à partir d'Appln-cadre comme ci-dessous.

@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();

    }

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X