Spring bean life cycle - Chrome driver 충돌 문제
개인 프로젝트에서 Chrome driver 를 사용하는데 Linux 버전에 대한 Chrome 옵션 설정을 추가하자마자 Spring Bean 생성 오류가 나면서 서버가 다운됐다. Chrome Driver - Spring 생명 주기 충돌 문제에 관한 포스팅을 하려한다.
+ Window의 경우에는 Chrome 옵션을 넣을 필요가 없으나 OS가 Linux 인 경우에는 Chrome 옵션(headerless 등)을 넣어야한다. (docker 에서는 linux 기반으로 돌리는데 linux에서는 chrome option 값이 필요함.)
스프링 빈 생성 주기 (Spring Bean Lifecycle)
- 객체 생성 → new를 통해 빈 객체가 생성됨. (@Component, @Bean 등)
- 의존성 주입 → @Autowired 등을 통해 필요한 의존성이 주입됨.
- 초기화 (InitializingBean, @PostConstruct) → 초기 설정 수행.
- 사용 → 빈이 애플리케이션에서 사용됨.
- 소멸 (DisposableBean, @PreDestroy) → 애플리케이션 종료 시 정리 작업 수행.
문제
Config 클래스의 생성자 안에서
- Window : new ChromeDriver() / Linux: new ChromeDriver(options)
이렇게 옵션을 줘서 전역 변수 driver 인스턴스를 생성했는데 spring 서버가 시작되지 않고 완전 다운됐다.
Ex) 에러 코드
Service 클래스의 생성자 안에서 driver 인스턴스 할당
<hide/>
private WebDriver webDriver;
@Value("${spring.profiles.active}")
private String profile;
@PostConstruct
void init() {
ChromeOptions options = new ChromeOptions();
System.setProperty("webdriver.chrome.driver", chromeDriverPath);
if (profile.equals("dev")) { // 리눅스 배포용 세팅
options.addArguments("--headless");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
log.info("Linux chrome 옵션 세팅 완료.");
webDriver = new ChromeDriver(options);
} else {
webDriver = new ChromeDriver();
}
}
Note) 결과
<hide/>
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'checkInController' defined in file [C:\Users\Ran\IdeaProjects\attendance-management\build\classes\java\main\com\automation\attendancemanagement\controller\CheckInController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'checkInService': Invocation of init method failed
Caused by: org.openqa.selenium.SessionNotCreatedException: Could not start a new session. Possible causes are invalid address of the remote server or browser start-up failure.
Command: [null, newSession {capabilities=[Capabilities {browserName: chrome, goog:chromeOptions: {args: [], extensions: []}}]}]
Caused by: java.io.UncheckedIOException: java.io.IOException: Cannot run program "C:\Users\Ran\Downloads\chromedriver-win64\chromedriver-win64": CreateProcess error=5, 액세스가 거부되었습니다
Caused by: java.io.IOException: Cannot run program "C:\Users\Ran\Downloads\chromedriver-win64\chromedriver-win64": CreateProcess error=5, 액세스가 거부되었습니다
Caused by: java.io.IOException: CreateProcess error=5, 액세스가 거부되었습니다
원인
위와 같이 새로운 크롬 드라이버 인스턴스를 생성하면 스프링 컨테이너가 관리하는 빈으로 등록되지 않는다.
( @Bean, @Component 로 등록하지 않았기 때문에 당연한 결과이다.)
따라서 @Bean 을 통해서 메서드 안에서 WebDriver를 빈으로 등록하는 과정이 필요하다.
해결 방법
ChromeDriver 를 bean 으로 등록하는 과정이 필요하다.
profiles 에 따라서 두 가지 bean 중 하나만 활성화되도록 결정한다.
Ex) 정상 코드
- @Bean을 등록함에 따라서Spring 컨테이너가 Web driver 를 관리하도록 한다.
- profile 값에 따라서 둘 중 하나의 bean만 생성하도록 설정한다.
<hide/>
@Slf4j
@Configuration
public class WebDriverConfig {
/*
@Bean
@Profile("local")
public WebDriver windowwebDriver() {
System.out.println(" 2. 빈생성 완료 - window");
return new ChromeDriver();
}
@Bean
@Profile("dev")
public WebDriver linuxWebDriver() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage"); // 리소스 부족 방지
System.out.println(" 2. 빈생성 완료 - linux");
return new ChromeDriver(options);
}*/