[GGB] Filter 등록하는 방법 4가지

Kim Hyen Su·2024년 7월 22일

GGB

목록 보기
8/13

# GGB # Spring Filter


개요

이전 포스팅을 통해서 기본적인 Filter를 구현하는 방법에 대해서 알아봤습니다. 그럼 실제 프로젝트에 어떻게 적용할 것인지에 대해서 추가로 확인해볼 필요가 있어서 해당 포스팅을 작성했습니다.

우선, LogFilter를 실제 프로젝트에 적용한다고 가정하겠습니다.

1. @Configuration 사용

LogFilter

@Slf4j
public class LogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        String requestURI = request.getRequestURI();
        log.info("[{}] LogFilter doFilter Start", requestURI);

        try {
            filterChain.doFilter(req, res);
        }finally {
            log.info("[{}] LogFilter doFilter End", requestURI);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

LoginCheckFilter

@Slf4j
public class LoginCheckFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        String requestURI = request.getRequestURI();
        log.info("[{}] LoginCheckFilter doFilter Start", requestURI);

        try {
            filterChain.doFilter(req, res);
        }finally {
            log.info("[{}] LoginCheckFilter doFilter End", requestURI);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

FilterConfig

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<Filter> logFilter(){
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new LogFilter());
        bean.setOrder(1);
        bean.addUrlPatterns("/*");
        return bean;
    }

    @Bean
    public FilterRegistrationBean<Filter> loginCheckFilter(){
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new LoginCheckFilter());
        bean.setOrder(1);
        bean.addUrlPatterns("/*");
        return bean;
    }
}

실행 결과

2024-07-23T00:44:36.650+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter Start
2024-07-23T00:44:36.651+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter Start
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter End
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter End

위 방식은 Filter 구현체를 정의 후 Configuration 어노테이션을 활용하여 FilterRegistrationBean을 통해 Filter Bean으로 등록해주는 방법입니다.

2. @Component 사용

LogFilter

@Slf4j
@Component
@Order(1)
public class LogFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LogFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LogFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LogFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LogFilter doFilter End", requestURI);
        }
    }
}

LoginCheckFilter

@Slf4j
@Component
@Order(2)
public class LoginCheckFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LoginCheckFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LoginCheckFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LoginFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LoginFilter doFilter End", requestURI);
        }
    }
}

실행 결과

2024-07-23T00:44:36.650+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter Start
2024-07-23T00:44:36.651+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter Start
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter End
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter End

위 방식은 별도의 설정 클래스 없이 직접 Component 어노테이션을 사용하여 필터를 빈으로 등록해주는 방식입니다. 해당 Filter 등록 시 @Order 어노테이션을 사용하여 순서를 설정해줄 수 있습니다. 하지만, 필터를 적용할 URL 패턴 설정은 불가능합니다.('/*'로 고정)

3. @WebFilter + @ServletComponentScan 사용

LogFilter

@Slf4j
@WebFilter
public class LogFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LogFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LogFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LogFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LogFilter doFilter End", requestURI);
        }
    }
}

LoginCheckFilter

@Slf4j
@WebFilter
public class LoginCheckFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LoginCheckFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LoginCheckFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LoginFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LoginFilter doFilter End", requestURI);
        }
    }
}

MainApplication

@ServletComponentScan
@SpringBootApplication
public class StudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(StudyApplication.class, args);
    }

}

실행 결과

2024-07-23T00:44:36.650+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter Start
2024-07-23T00:44:36.651+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter Start
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter End
2024-07-23T00:44:36.672+09:00  INFO 34980 --- [study] [nio-8080-exec-2] com.test.study.filter.LogFilter          : [/] LogFilter doFilter End

위 처럼 구현 시, ServletComponentScan 어노테이션을 통해 WebFilter 어노테이션이 붙은 클래스들을 필터로 활성화시켜줄 수 있습니다. 추가로, 어노테이션 attribute로 경로를 설정하여 해당 경로에 들어오는 요청 및 응답에 필터를 적용할 수 있습니다. 하지만, 필터 순서(Order)를 설정할 수 없으며 기본적으로 Filter 클래스명을 기준으로 오름차순으로 순서가 적용됩니다.

ex) AFilter > BFilter

4. @WebFilter + @Component 사용

LogFilter

@Slf4j
@Component
@WebFilter
@Order(1)
public class LogFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LogFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LogFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LogFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LogFilter doFilter End", requestURI);
        }
    }
}

LoginCheckFilter

@Slf4j
@Component
@WebFilter
@Order(2)
public class LoginCheckFilter implements Filter {
    @Override
    public void init(
            FilterConfig filterConfig
    ) throws ServletException {
        log.info("LoginCheckFilter init()");
    }

    @Override
    public void destroy() {
        log.info("LoginCheckFilter destroy()");
    }

    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        log.info("[{}] LoginFilter doFilter Start", requestURI);

        try {
            chain.doFilter(request, response);
        } finally {
            log.info("[{}] LoginFilter doFilter End", requestURI);
        }
    }
}

MainApplication

@ServletComponentScan
@SpringBootApplication
public class StudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(StudyApplication.class, args);
    }

}

실행 결과

2024-07-23T01:51:57.216+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter Start
2024-07-23T01:51:57.217+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LogFilter          : [/] LogFilter doFilter Start
2024-07-23T01:51:57.217+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LogFilter          : [/] LogFilter doFilter Start
2024-07-23T01:51:57.217+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter Start
2024-07-23T01:51:57.241+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter End
2024-07-23T01:51:57.241+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LogFilter          : [/] LogFilter doFilter End
2024-07-23T01:51:57.241+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LogFilter          : [/] LogFilter doFilter End
2024-07-23T01:51:57.241+09:00  INFO 29028 --- [study] [nio-8080-exec-4] com.test.study.filter.LoginCheckFilter   : [/] LoginCheckFilter doFilter End

위처럼 구현 후 실행해보니 @WebFilter를 사용한 LogFilter와 LoginCheckFilter가 2번씩 호출되었습니다. 이처럼 결과가 나온 이유는 @ServletComponentScan과 @Component 어노테이션이 동시에 적용되어 있기 때문입니다.

즉, 위 방법은 올바른 필터링 처리가 어렵습니다. 따라서, 사용하지 않는 것을 권장합니다.

마무리

결론적으로, 필터를 관리하는 수준에 따라서 구현 방식이 다릅니다. Filter의 Order와 요청 URL을 설정하여 Filter Chain을 구성하기 위해서는 @Configuration(1번) 방식을 사용해줍니다.

그것이 아닌 경우, 간단하게 @Component(2번) 방식 또는 @WebFilter(3번) 방식을 통해서 구현해보는 것도 좋습니다.

profile
백엔드 서버 엔지니어

0개의 댓글