스프링 레거시 XML설정 ㅡ> 자바 컨피그 클래스(스프링 레거시 환경에서 시큐리티 컨피그 클래스로 사용하기)

김지인·2023년 1월 14일
0
post-thumbnail

들어가기 앞서서 ..

세미 프로젝트 진행 중에 스프링 시큐리티를 적용해야 했다.
기존에 부트 환경에서 WebSecurityConfigurerAdapter를 상속받아서 클래스단에서 config를 작성하던 나에게는 xml은 새로웠고, 어려웠다. 그래서 레거시 환경에서 xml로 작성하던 시큐리티 환경설정을 config클래스로 변경해야 할 필요를 느꼇고 그러다 보니 숙제가 생겼다. 어떤 설정은 xml로 되어있고, 어떤 설정은 config클래스로 되어있으면 팀원들 입장에서 헷갈릴 수 도 있다고 생각이 들어 팀원들에게 양해를 구하고 기존 레거시의 xml설정을 전부다 config클래스로 변경하였다.


스프링 레거시에 기본적인 xml 환경설정 파일은 대표적으로 web.xml, root-context.xml, servlet-context.xml 이 있다. 하나씩 차례대로 알아보자


web.xml


우리가 익히 보던 web.xml파일이다. 해당 파일을 자바 config클래스로 만들기 위해 Spring Framework의 Initializer 클래스인 AbstractAnnotationConfigDispatcherServlet를 사용해서 구현할 것이다. 해당 클래스는 Dispatcher Servlet을 등록하고 루트 어플리케이션을 구성하여 Spring 웹 응용 프로그램을 초기화 하는 편리한 방법을 제공한다.

WebConfig.java

public class WebConfig 
extends AbstractAnnotationConfigDispatcherServletInitializer{

	@Override
	protected Class<?>[] getRootConfigClasses() {

		return new Class[] {RootConfig.class, SecurityConfig.class}; 
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] {ServletContext.class}; 
	}

	@Override
	protected String[] getServletMappings() {

		return new String[] {"/"}; 
	}

	
	@Override
	protected Filter[] getServletFilters() {
		 CharacterEncodingFilter characterEncodingFilter
         = new CharacterEncodingFilter();
	     characterEncodingFilter.setEncoding("UTF-8");
	     characterEncodingFilter.setForceEncoding(true);
	    
	    return new Filter[] { characterEncodingFilter }; 
	}
	
}

getRootConfigClasses()

@Override
	protected Class<?>[] getRootConfigClasses() {

		return new Class[] {RootConfig.class, SecurityConfig.class}; --- 1
	}

우리가 기존에 사용하던 xml파일의 경로를 설정해주는 web.xml의 상단 부분이다. (해당 파일은 초기 설정이라 security.xml 경로가 지정되어 있지않다.)
기존에 해당 root-context.xmlsecurity-context.xml의 경로를 지정 한 것처럼 모든 xml파일을 java config클래스로 변경해서 적용 시킬 것 이므로 RootConfig.classSecurityConfig.class를 등록해준다.


getServletConfigClasses()

@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] {ServletContext.class}; 
	}

@Override
	protected String[] getServletMappings() {
		return new String[] {"/"}; 
	}

servlet-context.xml를 등록하는 부분이다. web.xml에서는 /WEB-INF/spring/appServlet안에 있는 servlet-context.xml파일을 읽어서 실행시킬 것이다. 나는 servlet-context.xml 파일 또한 class로 만들어 사용할 것 이므로 ServletContext.class를 등록해준다. 또한 web.xml 이미지를 보면 servlet-mapping 부분의 url-pattern또한 getServletMappings()를 통해 설정한 것을 볼 수 있다.


getServletFilters()

@Override
	protected Filter[] getServletFilters() {
		 CharacterEncodingFilter characterEncodingFilter
         = new CharacterEncodingFilter();
	     characterEncodingFilter.setEncoding("UTF-8");
	     characterEncodingFilter.setForceEncoding(true);
	    
	    return new Filter[] { characterEncodingFilter }; 
	}

web.xml의 마지막 부분의 필터 부분이다. filter-class의 설정부분을 보자. org.springframework.web.filter.CharacterEncodingFilter클래스를 사용하고 있는데 java code를 보면 해당 클래스를 new 로 인스턴스로 만들고 xml파일과 똑같이 UTF-8로 설정하고 필터로 등록하는 것을 볼 수 있다.


이렇게 web.xml을 자바 클래스로 변경했다. 그렇다면 추가적으로 RootConfig.class, SecurityConfig.class, ServletContext.class 를 구현해보자.


servlet-context.xml

우리가 자주 보던 servlet-context.xml파일이다. resource의 위치를 지정하는 곳도 있고 뷰 리졸버 설정하는 부분도 있고, 컴포넌트 스캔경로도 지정할 수 있다.

ServletContext.java

@EnableWebMvc
@ComponentScan(basePackages = {"com.world.Y2K"})
public class ServletContext implements WebMvcConfigurer{
	
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		InternalResourceViewResolver bean = new InternalResourceViewResolver();
		
		bean.setViewClass(JstlView.class);
		bean.setPrefix("/WEB-INF/views/");
		bean.setSuffix(".jsp");
		
		registry.viewResolver(bean);  
		
	}
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

}

configureViewResolvers

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		InternalResourceViewResolver bean = new InternalResourceViewResolver();
		
		bean.setViewClass(JstlView.class);
		bean.setPrefix("/WEB-INF/views/");
		bean.setSuffix(".jsp");
		
		registry.viewResolver(bean);  
		
	}

뷰 리졸버를 설정하는 부분이다. ViewResolver 구현체인 InternalResourceViewResolver 클래스에 Prefix와 Suffix 설정을 해준 것을 볼 수 있다. 그리고 해당 클래스를 ViewResolverRegistry에 등록해준다.


addResourceHandlers

@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

resource를 지정하는 것은 직관적으로 동일하다.


@ComponentScan(basePackages = {"com.world.Y2K"})

해당 서블릿.xml파일이 스캔할 경로를 지정하는 것인데, 이는 클래스단에서 어노테이션을 통해 설정해주었다.


root-context.xml

스프링이 컨테이너에 올릴 수 있게 빈을 등록하는 root-context.xml파일이다. 이를 클래스로 변경해보자.

RootConfig.java


@Configuration
public class RootConfig {
 
    @Autowired
    private ApplicationContext applicationContext;
     
   @Bean
   public SqlSessionTemplate sqlSessionTemplate() throws Exception {
      return new SqlSessionTemplate((SqlSessionFactory) sqlSessionFactoryBean());
      
   }
   
   
   @Bean
   public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
      SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
      sqlSessionFactory.setConfigLocation(applicationContext.getResource("classpath:/mybatis-config.xml"));
      sqlSessionFactory.setDataSource(dataSource());
      return (SqlSessionFactory)sqlSessionFactory.getObject();
   }
   
   
   
   @Bean 
   public DataSourceTransactionManager transactionManager() {
      DataSourceTransactionManager transaction = new DataSourceTransactionManager();
      transaction.setDataSource(dataSource());
      return transaction;
   }
   
   @Bean
   public BasicDataSource dataSource() {
      BasicDataSource basicDataSource = new BasicDataSource();
      basicDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
      basicDataSource.setUrl("jdbc:oracle:thin:@localhost:1521:{pid}");
      basicDataSource.setUsername("{username}");
      basicDataSource.setPassword("{password}");
      return basicDataSource;
   }
   
   
   @Bean
   public CommonsMultipartResolver multipartResolver() {
      CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
      commonsMultipartResolver.setMaxUploadSize(100000000);
      commonsMultipartResolver.setMaxInMemorySize(100000000);
      return commonsMultipartResolver;
   }
   
}

(클래스경로에서 리소스를 가져오는 데 사용되는 ApplicationContext 객체를 의존성 주입한다.)



  @Bean
   public BasicDataSource dataSource() {
      BasicDataSource basicDataSource = new BasicDataSource();
      basicDataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
      basicDataSource.setUrl("jdbc:oracle:thin:@localhost:1521:{pid}");
      basicDataSource.setUsername("{username}");
      basicDataSource.setPassword("{password}");
      return basicDataSource;
   }

xml에 명시된 드라이버 클래스 이름, URL, 사용자 이름 및 암호와 같은 데이터 소스의 속성을 설정하는 클래스를 인스턴스로 만들고 위의 설정과 같이 set을 통해 설정해주고 해당 BasicDataSource의 인스턴스를 리턴해준다.


@Bean
   public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
      SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
      sqlSessionFactory.setConfigLocation(applicationContext.getResource("classpath:/mybatis-config.xml"));
      sqlSessionFactory.setDataSource(dataSource());
      return (SqlSessionFactory)sqlSessionFactory.getObject();
   }

처음에는 헷갈렷던 부분인데, 해당 xml파일에는 SqlSessionFactoryBean을 빈으로 등록한 것을 보고 자바 클래스 단에서 SqlSessionFactoryBean으로 반환하려니 에러가 발생했다. 알고보니 SqlSessionFactory의 구현체 이었고, 따라서 Mybatis SQL 세션을 생성하는 데 사용되는 SqlSessionFactoryBean의 인스턴스에 세팅을 하고 해당 인스턴스를 다운캐스팅을 통해 반환해준다.


 @Bean
   public SqlSessionTemplate sqlSessionTemplate() throws Exception {
      return new SqlSessionTemplate((SqlSessionFactory) sqlSessionFactoryBean());
      
   }

@Bean 
   public DataSourceTransactionManager transactionManager() {
      DataSourceTransactionManager transaction = new DataSourceTransactionManager();
      transaction.setDataSource(dataSource());
      return transaction;
   }

각 xml문서에 명시된 대로 규칙에 맞게 Mybatis SQL 세션을 관리하는 데 사용되는 SqlSessionTemplate을 빈으로 등록하고, 데이터 원본에 대한 트랙잭션을 관리하는데 사용되는 DataSourceTransactionManager을 빈으로 등록한다.


 @Bean
   public CommonsMultipartResolver multipartResolver() {
      CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
      commonsMultipartResolver.setMaxUploadSize(100000000);
      commonsMultipartResolver.setMaxInMemorySize(100000000);
      return commonsMultipartResolver;
   }

xml파일 설정과 동일하게 업로드 사이즈와 메모리 사이즈를 지정해준다.


스프링 시큐리티 config 클래스 만들기

xml파일들을 전부다 클래스로 바꾼 것은 스프링 시큐리티 설정을 xml파일에서 config클래스로 사용하기 위함이었다. 지금 현재 우리는 web.xml을 자바 클래스단에서 구현했기 때문에 스프링에 등록해야 할 녀석이 있다.

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer{

}

AbstractSecurityWebApplicationInitializer을 이용하면 web.xml에 spring security 필터를 직접 등록하지 않고도 사용할 수 있게 한다. Spring에 의해 자동으로 탐지되며 security config클래스의 설정을 자동으로 로드해준다.

여기 까지 했으면 수많은 구글에 있는 스프링시큐리티 config 클래스 설정들을 적용 시킬 수 있다. 이 글에서는 spring security의 환경설정에 관한 글이 아니므로, 여기서 마치겠다.

profile
에러가 세상에서 제일 좋아

0개의 댓글