Page History
Introduktion
Denne side beskriver de regler og bedste praksis, der anvendes i forbindelse med brug af dependency injection i NSP's Java-projekter. Det fokuserer specifikt på brugen af klasser som AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, og relaterede konfigurationsklasser i NSP's komponenter.
| Info |
|---|
DI.1.1 § Til Dependency Injection i NSP's komponenter |
...
skal spring frameworket benyttes. |
Konfigurationsklasser
Der oprettes en eller flere konfigurationsklasser, der er mærket med @Configuration. Dette er stederne, hvor Spring-beans (med @Bean) definerers og konfiguration af komponentene foretages. Der skal dermed på NSP anvendes konfigurationsklasser og ikke xml-filer.
Konfigurationsklasser bør skal være opdelt baseret på funktionalitet eller moduler. For eksempel kan der være en konfigurationsklasse for databasen, en for webservices, en for sikkerhed osv. Ved flere klasser samles de ved brug af @Import i en enkelt klasse.@Bean-metoder:
| Info |
|---|
DI.1.2 § Der skal benyttes java-konfigurationsklasser annoteret med @Configuration. Disse skal være logisk opdelt og navngivet |
Herunder eksmpel på en konfigurationsklasse fra NAS projektet.
| Code Block | ||||
|---|---|---|---|---|
| ||||
@Configuration
@PropertySource("classpath:notificationbroker.properties")
public class NotificationBrokerSetup {
public static final String SERVICE_NAME = "notificationbroker";
private static final Properties properties = Config.load(SERVICE_NAME);
@Bean
public Properties properties() {
return properties;
}
@Bean
public NotificationBrokerService notificationBrokerService(TopicMappingDAO topicMappingDao, Publisher publisher, AuditBuilderFactory auditBuilderFactory) {
return new NotificationBrokerServiceImpl(topicMappingDao, publisher, auditBuilderFactory);
}
... |
Brug @Bean-metoder i konfigurationsklasserne til at definere Spring-beans.
Navngiv metoder og beans fornuftigt, så det er nemt at forstå, hvilken rolle de spiller i applikationen (DAO, WsdlResponseGenerator, StatusResponseGenerator mm.) - i eksmplet fra NAS ovenfor Properties og notificationBrokerService.
| Info |
|---|
DI.1.3 § Der skal benyttes @Bean annotations til at definere spring-beans. Disse skal ligeledes være logisk opdelt og navngivet |
Ved flere klasser samles de ved brug af @Import i en enkelt klasse.
| Info |
|---|
DI.1.4 § Skal flere klasser samles logisk bruges @Import i en samlende java-klasse |
Eksempelvis samler NotificationBrokerServerSetup således konfigurationsklassen ovenfor og bla. en Database-konfigurationsklasse.
| Code Block | ||||
|---|---|---|---|---|
| ||||
@Configuration @Import({ NotificationBrokerSetup.class, PublisherSetup.class, DatabaseSetup.class }) public class NotificationBrokerServerSetup { @Bean public DataSource primaryDataSource(@Value("${datasource.jndi}") String jndiName) { JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); DataSource dataSource = dataSourceLookup.getDataSource(jndiName); return dataSource; } ... |
Der skal dermed ikke anvendes @Autowired i konfigurationsklasserne.
Afhængigheder og injection
...
Brug @Autowired for at injecte afhængigheder i HttpServletten. Dette valg er bevidst truffet for kun at implementere injektionen i denne servlet-klasse og ikke introducere yderligere kompleksitet eller struktur i andre dele af applikationen. Denne tilgang fokuserer på at holde koden inden for HttpServlet-konteksten mere kortfattet og læsbar, hvilket letter udvikling og vedligehold af den specifikke servlet.
| Info |
|---|
DI.1.5 § De definerede beans injectes med @Autowired annotationen i HttpServletten. Det er kun i HttpServletten dette må foretages. |
Herunder ses inklusionen af NotificationBrokerService-bean'en fra førnævnte konfigurationsklasse.
| Code Block | ||||
|---|---|---|---|---|
| ||||
@WebServlet("/*") public class NotificationBrokerServlet extends HttpServlet { ... @Value("${dgws.headers.required}") private boolean dgwsHeadersRequired; ... @Autowired private NotificationBrokerService service; .. |
...
. |
Derudover skal @Value annotationen bruges til properties (kan ligeledes ses i eksemplet ovenfor). Dette gælder både for servletten og i java-konfigurationsklasserne.
| Info |
|---|
DI.1.6 § I java-konfigurationsklasserne og servlet-klasserne skal @Value annotation bruges til at konfigurere værdier fra properties. |
Lifecycle Management
Opret og konfigurer en ApplicationContext ved hjælp af AnnotationConfigApplicationContext / AnnotationConfigWebApplicationContext. Det skal være en af disse to for at muliggøre brugen af konfigurationsklasserne.
| Info |
|---|
DI.1.7 § Der skal anvendes een af AnnotationConfigApplicationContext / AnnotationConfigWebApplicationContext som ApplicationContext-implementationsklasse. |
Denne skal konfigureres med de konfigurationsklasser der er relevante
Gem ApplicationContext'en gemmes i ServletContext for at gøre det den tilgængeligt for resten af applikationen.
Lifecycle Management:
Brug ServletContextListener-interfaces til at initialisere og rydde op i ApplicationContext i komponenten. Sørg for, at Ligeledes skal ApplicationContext lukkes korrekt, når webapplikationen stoppes.Injection i servlets:
| Info |
|---|
DI.1.8 § ApplicationContext'en skal oprettes og nedlægges ved hhv. contextInitialized og contextDestroyed på ServletContext'en. |
Her demonstreret ved NotificationBrokerens implementation:
| Code Block | ||||
|---|---|---|---|---|
| ||||
@WebListener
public class NotificationBrokerServletContextListener implements ServletContextListener {
protected static final String ANNOTATION_CONFIG_CONTEXT = "ANNOTATION_CONFIG_APPLICATION_CONTEXT";
...
@Override
public void contextInitialized(ServletContextEvent sce) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(NotificationBrokerServerSetup.class);
applicationContext.refresh();
sce.getServletContext().setAttribute(ANNOTATION_CONFIG_CONTEXT, applicationContext);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
Object ctx = sce.getServletContext().getAttribute(ANNOTATION_CONFIG_CONTEXT);
if(ctx instanceof AnnotationConfigApplicationContext) {
((AnnotationConfigApplicationContext)ctx).close();
}
}
|
På servlettens init-metode skal AnnotationConfigApplicationContext’en ApplicationContext’en hentes (via ServletContexten) og herigennem skal den aktuelle Servlet have sine afhængigheder injected. Dette skal foregå ved kald til autowireBean og give , hvor Servlet-instansen gives med. Hermed foretages den sidste sammenkædning af ApplicationContext'en, der nu er konfigureret med java-konfigurationsklasserne og Servletten. Med andre ord sørger det for, at afhængigheder injiceres i servletten ved at benytte Spring's autowiring-mekanisme baseret på konfigurationen i ApplicationContext'en.
| Info |
|---|
DI.1.9 § Servletten skal autowires programatisk via ApplicationContext'en |
Dette er demonstreret ved NotificationBroker-servletten her:
| Code Block | ||||
|---|---|---|---|---|
| ||||
@WebServlet("/*")
public class NotificationBrokerServlet extends HttpServlet {
...
@Override
public void init() throws ServletException {
Object o = getServletContext().getAttribute(NotificationBrokerServletContextListener.ANNOTATION_CONFIG_CONTEXT);
if(o != null && o instanceof AnnotationConfigApplicationContext) {
((AnnotationConfigApplicationContext)o).getAutowireCapableBeanFactory().autowireBean(this);
}
}
|
Bruger man derimod en JAX-WS genereret servlet kan denne autowiring ske ved brug af @PostConstruct annotationen, demonstreret ved eksemplet her fra FGVHR:
| Code Block | ||||
|---|---|---|---|---|
| ||||
public abstract class AbstractFgvhrWS {
@Resource
protected WebServiceContext context;
@PostConstruct
public void init() {
ServletContext servletContext = (ServletContext) context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
Object o = servletContext.getAttribute(ANNOTATION_CONFIG_CONTEXT);
((AnnotationConfigApplicationContext)o).getAutowireCapableBeanFactory().autowireBean(this);
}
|
I eksemplet her extender klasserne der implementerer de genererede JAX-WS klasser den abstrakte klasse.
Afsluttende
Samlet set udgør dokumentet her med eksempler en vejledning til hvordan DI i NSP's java-komponenter skal håndteres med brug af konfigurationsklasser, beans, autowiring og AnnotationConfigApplicationContext / AnnotationConfigWebApplicationContext.