Java Agent
개요
NetFUNNEL Java 에이전트는 Java 기반 Spring Boot 서버에서 NetFUNNEL 서버와 통신하는 전용 클라이언트입니다.
최소 요구 사항
- Java 1.7 이상
- Spring Boot 3.x 이상
외부 의존성
- gson: JSON 직렬화/역직렬화를 사용하기 위한 라이브러리
- jackson-module-kotlin: kotlin 사용을 위해 필요한 라이브러리 (Java 사용시)
동작 흐름
대기열 제어 지점은 NetFUNNEL 콘솔의 세그먼트 트리거 규칙을 통해 설정할 수 있습니다. 사용자가 접속한 페이지의 URL과 트리거 규칙을 비교하여 일치하는 경우 대기열이 적용됩니다.
대기 전: 페이지 로드 → 에이전트 초기화 → 트리거 규칙 매치 대기 중: 넷퍼넬 서버 요청 → 넷퍼넬 키 발급 → 대기실 페이지로 이동 대기 후: 서비스 페이지 진입 → 넷퍼넬 키 반납
에이전트 설치
라이브러리 주입
Kotlin DSL (build.gradle.kts)
implementation(files'libs/netfunnel-agent.jar')
implementation(com.google.code.gson:gson:2.9.1)
implementation (com.fasterxml.jackson.module:jackson-module-kotlin)
Groovy DSL (build.gradle)
implementation files('libs/netfunnel-agent.jar')
implementation 'com.google.code.gson:gson:2.9.1'
// Java 사용시
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
Interceptor 적용방법
경고
프로젝트 구조에 맞게 Interceptor와 Filter 중 하나만 선택하여 적용합니다. 두 방식 모두 동일한 NetFUNNEL 대기열 제어 기능을 제공하므로 중복으로 구현할 필요는 없습니다.
서버의 요청을 먼저 수신하는 Interceptor에 아래와 같은 코드를 작성합니다.
Kotlin
@Component
public class DemoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
NetFunnelInitializer initializer = getNetFunnelInitializer(requestUrl);
Netfunnel netfunnel = new Netfunnel(initializer, new NetFunnelServletService(request, response));
return netfunnel.run();
}
private NetFunnelInitializer getNetFunnelInitializer(String requestUrl) {
return NetFunnelInitializer.builder()
.clientId("{{CLIENT_ID}}")
.secretKey("{{SECRET_KEY}}")
.build();
}
}
Java
import com.stclab.Netfunnel;
import com.stclab.servlet.NetFunnelServletService;
import com.stclab.utils.NetFunnelInitialize;
@Component
public class DemoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
NetFunnelInitialize config = NetFunnelInitialize.Companion.builder()
.clientId("{{CLIENT_ID}}")
.secretKey("{{SECRET_KEY}}")
.build();
Netfunnel netfunnel = new Netfunnel(config, new NetFunnelServletService(request, response), null, null);
return netfunnel.run();
}
}
생성한 interceptor를 WebMvcConfigurer 의 addInterceptors 메서드를 override해서 등록합니다.
Kotlin
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final DemoInterceptor demoInterceptor;
@Autowired
public WebConfig(DemoInterceptor demoInterceptor) {
this.demoInterceptor = demoInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(demoInterceptor);
}
}
Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final DemoInterceptor demoInterceptor;
@Autowired
public WebConfig(DemoInterceptor demoInterceptor) {
this.demoInterceptor = demoInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(demoInterceptor)
.addPathPatterns("/**");
}
}
Filter 적용방법
서버의 요청을 먼저 수신하는 Filter에 아래와 같은 코드를 작성합니다.
Kotlin
@Component
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
NetFunnelInitializer initializer = getNetFunnelInitializer(requestUrl);
Netfunnel netfunnel = new Netfunnel(initializer, new NetFunnelServletService(request, response));
if (netfunnel.run()) {
chain.doFilter(servletRequest, servletResponse);
}
}
private NetFunnelInitializer getNetFunnelInitializer(String requestUrl) {
return NetFunnelInitializer.builder()
.clientId("{{CLIENT_ID}}")
.secretKey("{{SECRET_KEY}}")
.build();
}
}
Java
import com.stclab.Netfunnel;
import com.stclab.servlet.NetFunnelServletService;
import com.stclab.utils.NetFunnelInitialize;
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
NetFunnelInitialize config = NetFunnelInitialize.Companion.builder()
.clientId("{{CLIENT_ID}}")
.secretKey("{{SECRET_KEY}}")
.build();
Netfunnel netfunnel = new Netfunnel(config, new NetFunnelServletService(request, response), null, null);
if (!netfunnel.run()) {
return;
}
chain.doFilter(servletRequest, servletResponse);
}
}
생성한 Filter를 빈에 등록합니다.
Kotlin
@Configuration
@RequiredArgsConstructor
public class FilterConfig {
private final DemoFilter demoFilter;
@Bean
public FilterRegistrationBean<Filter> filterRegistrationBean() {
return new FilterRegistrationBean<>(demoFilter);
}
}
Java
@Configuration
@RequiredArgsConstructor
public class FilterConfig {
@Bean
public FilterRegistrationBean<Filter> filterRegistrationBean() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new DemoFilter());
registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration;
}
}
Initialize 설정 정보
| 필드 | 기본값 | 필수 | 설명 | 에이전트 버전 |
|---|---|---|---|---|
| clientId | N/A | O | 콘솔에서 발급받은 클라이언트 아이디를 입력합니다. | 4.0.1 이상 |
| secretKey | N/A | O | 콘솔에서 발급받은 암호화 키를 입력합니다. | 4.0.1 이상 |
| serverUrl | N/A | X | NetFUNNEL 서버의 URL입니다. CNAME을 사용하지 않고, clientId 기반의 URL 조합이 아닌 별도의 URL로 서버에 접근할 때 사용합니다. (기존 방식과의 호환성을 위해 지원됩니다.) | 4.0.1 이상 |
| settingUrl | N/A | X | NetFUNNEL 환경설정 파일의 URL입니다. CNAME을 사용하지 않고, clientId 기반의 URL 조합이 아닌 별도의 URL로 설정 파일을 불러올 때 사용합니다. (기존 방식과의 호환성을 위해 지원됩니다.) | 4.0.1 이상 |
| vwrPageUrl | N/A | X | NetFUNNEL VWR Page의 URL입니다. CNAME을 사용하지 않고, clientId 기반의 URL 조합이 아닌 별도의 URL로 대기실 페이지에 진입해야 할 때 지정합니다. | 4.0.1 이상 |
| returnKey | true | X | 사용자가 대기열을 통과해 페이지에 진입하면 즉시 다음 사용자가 입장할 수 있습니다. 옵션을 비활성화하면, 사용자가 페이지에 진입한 뒤에도 일정 시간동안 다음 사용자가 대기하게 됩니다. (타임아웃 설정은 콘솔의 세그먼트 설정 > 고급설정에서 가능합니다.) | 4.0.1 이상 |
| logLevel | Level.OFF | X | ch.qos.logback.classic.Level을 기반으로 로그 레벨을 설정하므로, 해당 의존성 추가가 필요합니다. 사용 가능 레벨: ERROR, WARN, INFO, DEBUG, TRACE, OFF | 4.0.1 이상 |
| goodBots | N/A | X | 선의의 봇(검색엔진 등)이 NetFUNNEL 진입 요청에서 제외되도록 설정합니다. 문자열의 배열로 값을 받습니다. 예시: ["Googlebot", "Bingbot"] | 4.0.1 이상 |
| userId | N/A | X | 이 값을 입력하면 화이트리스트 및 영구 차단 사용자 구분에 ID가 사용됩니다. 콘솔의 반복 요청 차단 > 사용자 설정 > 접속자 관리에서 설정한 ID가 적용됩니다. | 4.0.1 이상 |
| vwrPageDomain | N/A | X | CNAME 도메인만으로 VWR Page URL을 구성할 때 사용합니다. 예시: https://vwr.example.com | 4.0.1 이상 |
| cookieDomain | N/A | X | 발급되는 NetFUNNEL 쿠키의 도메인(Domain) 값을 직접 지정할 수 있습니다. | 4.0.1 이상 |
에이전트 적용
대기열 제어 지점은 NetFUNNEL 콘솔의 세그먼트 트리거 규칙을 통해 설정할 수 있습니다. 사용자가 접속한 페이지의 URL과 트리거 규칙을 비교하여 일치하는 경우 대기열이 적용됩니다.
설정 옵션
- Logical Operator: 두 개 이상의 트리거 규칙을 생성할 때, 서로의 관계를 and 또는 or 연산자로 결정합니다.
- Validator: 트리거 규칙이 적용될 대상의 최상위 범위를 정의합니다. 현재는 URL만 제공하고 있습니다.
- Component: Validator에 의해 정의된 범위 내에서 더 세부적으로 규칙을 적용할 대상을 지정합니다. 이는 URL 전체 또는 경로(Path) 등이 될 수 있으며, 특정 페이지나 자원에 규칙을 적용하는 데 사용됩니다.
- Negate: 설정한 조건의 반대 경우를 적용하고 싶을 때 사용합니다. 예를 들어, 특정 조건이 '참'이 아닐 때 규칙을 적용하고자 할 때 이 옵션을 활성화합니다.
- Match: 규칙이 적용될 조건의 유형을 정의합니다. 'Equals', 'Exists' 등의 옵션을 통해 특정 값과 일치하는 경우, 또는 특정 조건이 존재하는 경우 등을 기준으로 규칙을 적용할 수 있습니다.
- Value: 규칙 적용 시 비교 대상이 되는 구체적인 값을 지정합니다. 이 값은 'Match' 조건과 함께 사용되어, 규칙이 어떤 경우에 활성화될지를 결정합니다.
- Aa: Value에 대해 비교할 때 대소문자를 구분할지 결정합니다.
Match 옵션
- Exists: URL에 해당 Component가 존재하는지 확인합니다. (Component가 Path일 때만 사용 가능합니다.)
- Equals: Component의 값과 Value가 완전히 일치하는지를 확인합니다.
- Contains: Component의 값에 지정된 Value가 포함되어 있는지를 확인합니다.
- StartsWith: Component의 값이 지정된 Value로 시작하는지를 확인합니다.
- EndsWith: Component의 값이 지정된 Value로 끝나는지를 확인합니다.
트리거 규칙 테스트
대기열을 적용하고자하는 URL이 트리거 규칙에 부합하는지 미리 확인하기 위하여 사전에 테스트할 수 있습니다.