쉽게 쉽게

[프로젝트 설정] XML과 Java Configuration 설정 방식 본문

CS/CS

[프로젝트 설정] XML과 Java Configuration 설정 방식

곱마2 2024. 10. 13. 21:01
반응형

▤ 목차

    Spring 프로젝트에서 애플리케이션의 설정을 구현하는 방식은 XML과 Java Configuration이 있다.

    이 둘의 장단점과 xml을 java configuration 방식으로 변환하는 방법을 알아보고자 한다.

    1. XML 설정 (XML-based Configuration)

    이 방식은 XML 파일 내에 태그를 사용하여 애플리케이션의 빈과 의존성을 선언한다.

    <bean id="ExBean" class="com.example.ExClass">
        <property name="name" value="bob" />
    </bean>

    1. 장점

    • 수정 및 배포 용이: 설정이 Java 코드와 분리되어 있어, 설정 파일을 수정하더라도 애플리케이션 코드를 수정하지 않고도 배포가 가능하다.
    • 코드와 분리된 설정: 코드가 아닌 XML 파일을 통해 설정을 관리하므로, 개발자 외에 다른 관리자도 설정 파일을 쉽게 수정할 수 있다. (중앙에서 관리하기 용이)
    • 가독성이 좋음: XML 파일은 사람이 읽고 쓰기 쉬운 형태로 되어 있어, 구성 정보의 가독성이 높다. 이는 특히 애플리케이션의 구성이 복잡하지 않은 경우에 유리할 수 있다.
    • 기존 프로젝트와의 호환성: Spring 2.x 이전부터 사용되던 방식으로, 레거시 시스템과의 호환성을 유지하는 데 유리하다.

    2. 단점

     

    • 빈약한 정보: XML은 모든 설정을 명시적으로 나타내야 하므로, 클래스를 지정하는 것도 상당히 번거롭다. 또한 XML은 단순 텍스트이기 때문에 해당 클래스가 다른 클래스와 어떤 관계를 갖는지 알 수 없다.
    • 타입 안전성 부족: XML 설정에서는 컴파일 타임에 오류를 확인할 수 없으며, 설정 오류는 런타임 시점에만 확인된다. (즉 BreakPoint를 찍어볼 수 없고 어디서 오류가 났는지 확인하기 어렵다.)
    • 유지보수 어려움: 설정이 복잡해지면 관리가 어려워지고, 특히 대규모 프로젝트에서 XML 파일이 길어지면 가독성이 떨어질 수 있다.

     

    2. Java Configuration (Java-based Configuration)

    이 방식은 애플리케이션의 구성 정보를 자바 클래스를 사용하여 정의하는 방법이다.

    @Configuration 어노테이션을 사용하여 구성 클래스를 선언하고, @Bean 어노테이션을 사용하여 빈(Bean)을 정의한다.

    @Configuration
    public class AppConfig {
    
        @Bean
        public ExClass ExBean() {
            return new ExClass("bob");
        }
    }

    1. 장점

     

    • 타입 안전성: 자바 코드를 사용하기 때문에 컴파일 시점에서 오류를 발견할 수 있으며, IDE의 지원을 받아 리팩토링과 코드 탐색이 용이하다. (즉 BreakPoint를 찍어볼 수 있고 구동 전에 오류를 알려준다.)
    • 유연성: 조건부 로직을 적용(@Conditional), 환경 설정(@Profile), AOP 설정 등 복잡한 설정을 Java 코드로 더 쉽게 작성할 수 있다.
    • 많은 정보: Java 코드로 작성된 클래스의 정보들(패키지, 클래스 이름, 접근 제한자, 상속/구현 등)까지 얻을 수 있다.

     

    2. 단점

     

    • 코드와 설정의 결합: 설정이 코드에 포함되므로 설정 변경을 위해서는 코드 수정을 해야 하며, 이는 배포 과정에서 코드를 다시 컴파일해야 할 수 있다.
    • 학습 곡선: 기존 XML 설정에 익숙한 개발자에게는 적응하는 데 시간이 필요할 수 있다.

     

    3. 요약

    유연하고 타입 안전한 설정이 필요한 경우 Java Configuration을 사용하는 것이 더 유리하며,

    기존 레거시 프로젝트와의 호환성이 중요한 경우 XML 설정을 사용할 수 있다.

    3. XML 설정 --> Java Configuration으로 전환

    변경 전 web.xml 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" 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 https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
    	<!-- 한글설정 -->
    	<filter>
    		<filter-name>encodingFilter</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>
    	<filter-mapping>
    		<filter-name>encodingFilter</filter-name>
    		<url-pattern>/*</url-pattern> 
    	</filter-mapping>	
    
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>/WEB-INF/spring/root-context.xml</param-value>
    	</context-param>
    
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener
    		</listener-class>
    	</listener>
    
    	<servlet>
    		<servlet-name>appServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet
    		</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml
    			</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>appServlet</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    
    </web-app>

    xml 방식에서는 web.xml에 다양한 설정들이 정의되어 있는 것이 보통이다.

    살펴보면 인코딩, DispatcherServlet, servletMapping 등의 설정이 정의되어 있는 것을 알 수 있다.

    이를 Java Configuration 방식으로 변경하기 위해서는 web.xml처럼 각 설정 정보를 담고 있는 java 클래스를 만들어 관리하면 된다.

    xml 파일로 구성되어 있는 설정을 Java 방식으로 바꿔주는 단계는 이렇다.

    1. pom.xml을 수정하여 web.xml를 사용하지 않겠다는 설정 추가(web.xml을 제거해도 무방)
    2. web.xml 설정 파일에 대응되는 java 클래스 생성
    3. 각각의 클래스를 세팅 

    1. pom.xml 설정 추가(web.xml 설정 사용 금지)

    필자는 web.xml을 남겨놓고 싶어서 이런 설정을 했다.

    특별한 이유가 없다면 web.xml을 제거해도 무방하다.

    <plugin>
    	<groupId>org.apache.maven.plugins</groupId>
    	<artifactId>maven-war-plugin</artifactId>
    	<version>3.2.0</version>
    	<configuration>
    	<failOnMissingWebXml>false</failOnMissingWebXml>
    	</configuration>
    </plugin>

    2. WebConfig 생성 (java 설정을 모아놓는 곳 = web.xml)

    변경 후 WebConfig 파일

    package kr.board.config;
    
    import javax.servlet.Filter;
    import org.springframework.web.filter.CharacterEncodingFilter;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    //web.xml을 대신해서 만드는 config
    public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
    
    	@Override
    	protected Class<?>[] getRootConfigClasses() {
    	// TODO Auto-generated method stub
    		return new Class[] {RootConfig.class};
    	}
    	@Override
    	protected Class<?>[] getServletConfigClasses() {
    		return new Class[] {ServletConfig.class};
    	}
    	
    	@Override
    	protected String[] getServletMappings() {
    	return new String[] {"/"};
    	}
    	
    	//web.xml의 인코딩 대체
    	@Override
    	protected Filter[] getServletFilters() {
    		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
    		encodingFilter.setEncoding("UTF-8");
    		encodingFilter.setForceEncoding(true);
    		return new Filter[]{encodingFilter};
    	}
    	
    }

    web.xml에서 사용하던 설정들을 java 클래스로 바꿔서 각각 설정해주면 된다.

    필자는 servlet-context.xml에 viewResolver 설정했었기 때문에 그에 맞는 ServletConfig 클래스를 생성했다. 

    root-context.xml에 DB 커넥션 정보를 설정했었기 때문에 그에 맞는 RootConfig 클래스를 생성했다.

    3. RootConfig와 ServletConfig 생성

    변경 전 root-context.xml 파일

    <?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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
    		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
    		
    	<!-- mysql  -->
    	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
    		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/com?serverTimezone=UTC"/>
    		<property name="username" value="사용자 저의"/>
    		<property name="password" value="사용자 정의"/>
    	</bean>
    
    	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
    		<constructor-arg ref="hikariConfig" />
    	</bean>	
    
    	<mybatis-spring:scan base-package="사용하는 Mapper 경로"/>	
    
    	<bean class="org.mybatis.spring.SqlSessionFactoryBean">
    		<!-- connection pool 연결  -->
    		<property name="dataSource" ref="dataSource" />
    	</bean>	
    		
    </beans>

    변경 후 RootConfig(DB 설정) 생성

    package kr.board.config;
    
    import javax.sql.DataSource;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.core.env.Environment;
    import com.zaxxer.hikari.HikariConfig;
    import com.zaxxer.hikari.HikariDataSource;
    
    //root-context.xml 대신 만들어짐
    @Configuration
    @MapperScan(basePackages = {"사용하는 mapper 경로 입력"})
    @PropertySource({ "classpath:persistence-mysql.properties"})
    public class RootConfig {
    	
    	//properties 불러오려면 사용해야하는 클래스
    	@Autowired
    	private Environment env;
    	@Bean
    	public DataSource myDataSource() {
    		HikariConfig hikariConfig=new HikariConfig();
    		hikariConfig.setDriverClassName(env.getProperty("jdbc.driver"));
    		hikariConfig.setJdbcUrl(env.getProperty("jdbc.url"));
    		hikariConfig.setUsername(env.getProperty("jdbc.user"));
    		hikariConfig.setPassword(env.getProperty("jdbc.password"));
    		HikariDataSource myDataSource=new HikariDataSource(hikariConfig);
    	return myDataSource;
    	}
    	@Bean
    	public SqlSessionFactory sessionFactory() throws Exception{
    		SqlSessionFactoryBean sessionFactory=new SqlSessionFactoryBean();
    		sessionFactory.setDataSource(myDataSource());
    		return (SqlSessionFactory)sessionFactory.getObject();
    	}
    
    }

    변경전 servlet-context.xml 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/mvc"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:beans="http://www.springframework.org/schema/beans"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
    		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    	<annotation-driven />
        
    	<resources mapping="/resources/**" location="/resources/" />
        
    	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<beans:property name="prefix" value="/WEB-INF/views/" />
    		<beans:property name="suffix" value=".jsp" />
    	</beans:bean>
    	
    	<context:component-scan base-package="사용하는 컨트롤러 경로" />
    
    </beans:beans>

    변경 후 ServletConfig(ViewResolver 설정) 생성

    package kr.board.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import org.springframework.web.servlet.view.InternalResourceViewResolver;
    
    //servlet-context.xml 대신 만들어짐
    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = {"사용하는 컨트롤러 경로 입력"})
    public class ServletConfig implements WebMvcConfigurer{
    	@Override
    	public void configureViewResolvers(ViewResolverRegistry registry) {
    	InternalResourceViewResolver bean=new InternalResourceViewResolver();
    	bean.setPrefix("/WEB-INF/views/");
    	bean.setSuffix(".jsp");
    	registry.viewResolver(bean);
    	}
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    	registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    	}
    }

    이런 식으로 web.xml에 존재하는 설정들을 java 클래스에 맞게 만들어주면 된다.

    이외의 설정도 대응되는 java 클래스를 활용하여 config를 구현해 나가면 될 것이다.  

    잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다.

    https://mangkyu.tistory.com/158

     

    [Spring] XML 설정보다 Java 설정을 사용해야 하는 이유

    Spring을 제대로 이용하기 위해서는 Spring이 갖는 기본 개념과 철학을 이해해야 한다. 이번에는 Spring에 입문하는 사람들을 위해 Spring에 대해 이해할 수 있는 내용을 작성해보고자 한다. 1. XML 설정

    mangkyu.tistory.com

    https://f-lab.kr/insight/java-configuration-vs-xml-setting

     

    자바 컨피그레이션과 XML 설정의 비교: 스프링 프로젝트 구성 방법

    스프링 프로젝트 구성 방법으로서 자바 컨피그레이션과 XML 설정의 개념, 장단점을 비교하고, 각 방식의 선택 기준에 대해 설명합니다.

    f-lab.kr

    반응형

    'CS > CS' 카테고리의 다른 글

    SQL Mapper와 ORM이란?  (0) 2023.05.14
    멀티태스킹, 멀티프로세싱, 멀티스레딩  (1) 2023.05.07
    컴퓨터 구성요소  (0) 2023.05.07
    XML, JSON  (0) 2023.04.05
    API, REST, REST API  (0) 2023.04.01