Keresés tartalomra
Kategóriák
Címkék
- Java
- Spring
- Python
- IoC
- Android
- DI
- Dagger
- Thymeleaf
- Markdown
- JDK11
- AOP
- Aspect
- Captcha
- I18n
- JavaSpark
- Microframework
- Testing
- JUnit
- Security
- JWT
- REST
- Database
- JPA
- Gépház
- WebFlux
- ReactiveProgramming
- Microservices
- Continuous Integration
- CircleCI
- Deployment Pipeline
- Docker
- Mocking
- LogProcessing
- PlantUML
- UML
- Modellezés
- OAuth2
- Node.js
- DevOps
- Websocket
Spring XML konfiguráció cseréje Java alapúra
A Spring XML alapú konfigurálhatósága a mai napig egy teljesen jól használható megoldás. Rengeteg leírás lelhető fel róla, sőt egészen úgy tűnik, mintha ezt preferálnák mind a Spring készítői, mind a fejlesztők. Azonban a Java/annotáció alapú konfigurációnak megvan az a nagy előnye, hogy az alkalmazás forráskódja konzisztensen tartható az XML konfigurációs fájlok (közel) teljes eliminálásával. Nem mellesleg Java fejlesztőként – személyes véleményem szerint – hálásabb feladat Java, mint XML kódot írni.
Mielőtt belevágnánk, fontos megjegyzés: a cikk végén levő link egy GitHub repository linkje, melyen megtalálható a példaalkalmazás teljes forrása. A master branch-en „ömlesztve” látható a kettő, a „config-xml” illetve „config-java” branch-ekre váltva azonban külön-külön is megtekinthetőek.
A konfiguráció cseréjét többféle megközelítésből is elkezdhetjük. Lehet részleges is, webes alkalmazás esetén meghagyhatjuk például a WAR alkalmazás csomagok által igényelt web.xml servlet inicializáló állományt, azonban a konzisztencia (és a cikkemben leírt példa összetettségének növelése) érdekében teljes csere végrehajtását fogom bemutatni. Alább látható az eredeti (XML alapú) alkalmazáskonfiguráció valamint a servlet inicializáló (web.xml) állomány tartalma. A továbbiakban minden fontosabb szekció részletesen tárgyalásra – és cserére – kerül majd.
XML konfiguráció
Az appcontext-config.xml állomány tartalmazza az alkalmazás alap-kontextus konfigurációját. Mivel nagyon pici az alkalmazás, most gyakorlatilag ez üres, de alapvetően ide (is) bean definíciók fognak kerülni.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
</beans>
A dispatcher-config.xml állomány már sokkal fontosabb szereppel bír, gyakorlatilag az összes MVC beállítást ő kell, hogy tartalmazza.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
<!-- (1) -->
<context:component-scan base-package="hu.psprog.dev.tutorial.web.controller" />
<!-- (2) -->
<mvc:annotation-driven />
<!-- (3) -->
<bean id="defaultViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/view/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Az (1)-es paraméterrel adható meg az MVC controllerek helye. A Spring 3-as verziója előtt azokat is manuálisan kellett bean-ként létrehozni, szerencsére az újabb verziókban – még XML konfiguráció használata mellett is – használhatóak a @Controller
annotációk az MVC controllerek megjelölésére.
A (2)-es paraméter engedélyezi az annotációk használatát – az (1)-es ponttal együtt használandók.
A (3)-as paraméter a nézet feloldását végrehajtó bean definíciója. Mivel most a példa kedvéért egyszerű JSP nézeteket használunk, az InternalResourceViewResolver osztályból példányosított bean-t használunk a feladatra. A prefix és szuffix paraméterek közé lesz beszúrva a tényleges nézetnév.
A legnagyobb feladat azonban a web.xml állományra hárul. Ezen konfigurációs fájl feladata a servlet elindítása és a kontextus felépítése. A web.xml Java EE standard konfigurációs fájl, bármilyen Java EE alkalmazást írunk, erre szükség lesz a servlet indításához (kivéve inicializáló használatával, de erről később).
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- (1) -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/dispatcher-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- (2) -->
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- (3)-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/appcontext-config.xml</param-value>
</context-param>
<!-- (4) -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- (5) -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- (6) -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Az (1)-es szekció feladata a dispatcher létrehozása és konfigurálása. A dispatcher fogja elcsípni a HTTP kéréseket, és továbbítani a megfelelő feldolgozók felé. A konfigurációját a dispatcher-config.xml állományból fogja gyűjteni, illetve a load-on-startup értékkel megadható, milyen prioritással induljon el a servlet a konténerbe való telepítés után.
A (2)-es szekció feladata csupán annyi, hogy a dispatcher hatáskörének gyökerét állítja be. Ez jelenleg „/”, tehát minden kérésre ez a servlet fog reagálni.
A (3)-as szekcióban levő paraméter neve kötelezően az itt látható, mivel ő adja meg a dispatcher számára az alkalmazás alap-konfigurációs állományát – ami jelen esetben az appcontext-config.xml.
A (4)-es szekcióban létrehozott ContextLoaderListener példány fogja végül ténylegesen felépíteni a kontextust, így ez is nagyon fontos elem.
Az (5)-ös és (6)-os szekciók opcionálisak, bár szinte biztosan szükség lesz rájuk: a karakterkódolás beállítása a feladatuk. Jelen esetben UTF-8 használatára kényszerítem a servlet-et, a „/*” minta miatt pedig minden kérésre érvényes lesz a filter használata.
Java/annotációs konfiguráció
Most hogy láttuk az XML alapú konfigurációt, egy laza mozdulattal dobjuk ki az egészet, és írjuk át Java/annotáció alapúra. A teljes példaalkalmazásban látható lesz, de fontos megemlítenem, hogy az alkalmazás POM-jában külön jelezni kell, hogy a** továbbiakban nem lesz web.xml**. Ez azért fontos, mert – mint említettem – minden Java EE alkalmazásnak kötelezően rendelkeznie kell ilyennel. Azonban mi ezt most egy inicializálóra fogjuk cserélni. De előbb:
Az appcontext-config.xml állományt felváltja az AppContextConfig osztály.
package hu.psprog.dev.tutorial.web.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("hu.psprog.dev.tutorial.web")
public class AppContextConfig {
}
A szemfülesebbeknek feltűnhet, hogy némiképp több értékes információval bír, mint az XML-testvére. Megjelenik a @Configuration
annotáció, mely azt fogja jelezni a kontextus betöltőnek (melyet most külön nem is kell majd létrehoznunk), hogy ez az osztály konfigurációs paramétereket, bean definíciókat fog tartalmazni. A @ComponentScan
pedig egy (vagy több) csomagnevet vár, ahol a további konfigurációs osztályok, controllerek, bean-ek, komponensek, egy szóval minden olyan elem található, melyet a Spring-nek felügyelni kell.
Továbbhaladva a dispatcher-config.xml állomány helyét is átveszi a DispatcherConfig osztály.
package hu.psprog.dev.tutorial.web.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
public class DispatcherConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver defaultViewResolver() {
InternalResourceViewResolver viewResolver =
new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Nem meglepő módon ő is megkapja a @Configuration
annotációt, továbbá kapni fog egy @EnableWebMvc
nevűt is. Emlékszünk az <mvc:annotation-driven />
szekcióra? Ez annak a megfelelője Java konfigurációban. Az osztályban létrehozott bean definíció pedig a nézetfeloldásért felelős – pont, mint az XML konfigurációban.
Végül már csak a web.xml cseréje maradt hátra. Helyette fogunk inicializálót használni, méghozzá az alábbi módon:
package hu.psprog.dev.tutorial.web.init;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import hu.psprog.dev.tutorial.web.config.AppContextConfig;
public class ApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// (1)
AnnotationConfigWebApplicationContext appContext =
new AnnotationConfigWebApplicationContext();
appContext.register(AppContextConfig.class);
// (2)
ServletRegistration.Dynamic dispatcherServlet =
servletContext.addServlet("mvc-dispatcher",
new DispatcherServlet(appContext));
// (3)
dispatcherServlet.addMapping("/");
dispatcherServlet.setLoadOnStartup(1);
// (4)
FilterRegistration characterEncodingFilter =
servletContext.addFilter("CharacterEncodingFilter",
new CharacterEncodingFilter());
characterEncodingFilter.setInitParameter("encoding", "UTF-8");
characterEncodingFilter.setInitParameter("forceEncoding", "true");
characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
}
}
Az inicializáló létrehozásához implementálni kell a WebApplicationInitializer interfészt, melynek csupán egy metódusa van, ami az onStartup() nevet viseli. A Tomcat, a servlet indításakor meg fogja találni ezt a leszármazott osztályt, majd meghívja azt, átadva neki egy konfigurálásra váró servlet kontextus objektumot. Innentől nagyjából ugyanaz a helyzet, mint XML alapú konfiguráció esetén, azonban külön ContextLoaderListener-re ez esetben nem lesz szükség.
Az (1)-es szekció létrehoz egy annotáció alapú web alkalmazás kontextust (a web MVC környezet csak így fog működni, szóval fontos, hogy ilyet hozzunk létre), melynek szüksége lesz az alap-konfigurációt beállító konfigurációs osztály nevére. A register() metódussal akár több ilyet is hozzáadhatunk, de jobb, ha a konfigurációs osztály importálja (vagy keresteti meg) a többit.
A (2)-es szekció regisztrálja az alkalmazás saját dispatcher servlet-jét a servlet kontextusban – ezzel összekapcsolja a konténert (Tomcat) és az alkalmazást. A dispatcher-nek át kell adni létrehozáskor az alkalmazás kontextus példányt, így a servlet elindulásával a kontextus is azonnal fel fog épülni.
A (3)-as szekció az XML alapú konfigurációból ismerős beállításokat végzi el: a dispatcher minden kérésre reagálni fog, és a konténer elindulása után a servlet magas prioritással (azonnal) be fog töltődni.
Végül a (4)-es szekció a karakterkódolás beállításáért felel.
Konklúzió
A fenti példából remélem jól látható volt, milyen könnyedén átjárható a két konfigurációs megközelítés. Természetesen mindkettő jó, mindkettő használható, ízlés – és kényszer – válogatja, mikor melyiket érdemes – vagy kell – használni. Az előnyök és hátrányok egyaránt megvannak mindkét oldalon. Az XML alapú konfigurációhoz sokkal több segédlet található, valamint a web.xml állomány használata miatt a Java EE standardokat is tiszteletben tartjuk. A Java/annotáció alapú konfiguráció viszont egységessé teszi az alkalmazás forráskódját, mivel teljesen meg lehet szabadulni az XML konfigurációs fájloktól. Helyenként könnyebb a használata, ugyanakkor az XML paraméterek némiképp egységesebbnek érződnek.
Komment írásához jelentkezz be
Bejelentkezés
Még senki nem szólt hozzá ehhez a bejegyzéshez.