Das mit Anmerkungen versehene Feld @Autowired
ist darauf zurückzuführen, null
dass Spring nichts über die Kopie weiß, mit der MileageFeeCalculator
Sie erstellt haben, new
und nicht wusste, dass sie automatisch verdrahtet werden soll.
Der IoC-Container (Spring Inversion of Control) besteht aus drei logischen Hauptkomponenten: einer Registrierung (der so genannten ApplicationContext
) von Komponenten (Beans), die von der Anwendung verwendet werden können, und einem Konfigurationssystem, das die Abhängigkeiten von Objekten in sie einfügt, indem die Abhängigkeiten mit Beans im Kontext und ein Abhängigkeitslöser, der eine Konfiguration vieler verschiedener Beans anzeigen und bestimmen kann, wie diese in der erforderlichen Reihenfolge instanziiert und konfiguriert werden.
Der IoC-Container ist keine Zauberei und kann nur dann über Java-Objekte informiert werden, wenn Sie ihn irgendwie darüber informieren. Wenn Sie anrufen new
, instanziiert die JVM eine Kopie des neuen Objekts und gibt sie direkt an Sie weiter - sie durchläuft nie den Konfigurationsprozess. Es gibt drei Möglichkeiten, wie Sie Ihre Beans konfigurieren können.
Ich habe den gesamten Code mit Spring Boot zum Starten in diesem GitHub-Projekt veröffentlicht . Sie können sich für jeden Ansatz ein vollständig laufendes Projekt ansehen, um alles zu sehen, was Sie benötigen, damit es funktioniert. Tag mit dem NullPointerException
:nonworking
Injizieren Sie Ihre Bohnen
Am besten lassen Sie Spring alle Ihre Bohnen automatisch verdrahten. Dies erfordert die geringste Menge an Code und ist am wartbarsten. Damit die automatische Verdrahtung so funktioniert, wie Sie es möchten, gehen Sie MileageFeeCalculator
wie folgt vor :
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
Wenn Sie eine neue Instanz Ihres Serviceobjekts für verschiedene Anforderungen erstellen müssen, können Sie die Injektion weiterhin mithilfe der Spring Bean-Bereiche verwenden .
Tag, das durch Injizieren des @MileageFeeCalculator
Serviceobjekts funktioniert :working-inject-bean
Verwenden Sie @Configurable
Wenn Sie wirklich Objekte benötigen, die mit erstellt wurden new
, um automatisch verdrahtet zu werden, können Sie die Spring- @Configurable
Annotation zusammen mit AspectJ-Weben zur Kompilierungszeit verwenden , um Ihre Objekte zu injizieren. Dieser Ansatz fügt Code in den Konstruktor Ihres Objekts ein, der Spring darüber informiert, dass er erstellt wird, damit Spring die neue Instanz konfigurieren kann. Dies erfordert ein wenig Konfiguration in Ihrem Build (z. B. Kompilieren mit ajc
) und @EnableSpringConfigured
Aktivieren der Spring-Laufzeitkonfigurationshandler ( mit der JavaConfig-Syntax). Dieser Ansatz wird vom Roo Active Record-System verwendet, damit new
Instanzen Ihrer Entitäten die erforderlichen Persistenzinformationen einspeisen können.
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Tag, das @Configurable
für das Serviceobjekt verwendet wird:working-configurable
Manuelle Bohnensuche: nicht empfohlen
Dieser Ansatz eignet sich nur für die Schnittstelle mit Legacy-Code in besonderen Situationen. Es ist fast immer vorzuziehen, eine Singleton-Adapterklasse zu erstellen, die Spring automatisch verdrahten und den Legacy-Code aufrufen kann. Es ist jedoch möglich, den Spring-Anwendungskontext direkt nach einer Bean zu fragen.
Dazu benötigen Sie eine Klasse, auf die Spring einen Verweis auf das ApplicationContext
Objekt geben kann:
@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;
}
}
Dann kann Ihr Legacy-Code getContext()
die benötigten Beans aufrufen und abrufen:
@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);
}
}
Tag, das funktioniert, indem das Serviceobjekt im Spring-Kontext manuell nachgeschlagen wird: working-manual-lookup
F
im Konstruktor einer anderen Bean aufgerufen wirdS
. In diesem Fall übergeben Sie die erforderliche BeanF
als Parameter an denS
Konstruktor der anderen Beans und kommentieren Sie den Konstruktor vonS
mit@Autowire
. Denken Sie daran, die Klasse der ersten BeanF
mit zu kommentieren@Component
.