안녕하세요 오늘은 Spring Boot Configuration 설정 방법에 대해 포스팅해보겠습니다.
위의 코드를 보시면 빨간 줄로 " 자동 주입을 할 수 없습니다. 해당 타입의 bean을 찾을 수 없습니다. " 과 같은 문구가 나옵니다. 하지만 실제 프로그램을 실행시켰을 때 이상 없이 잘 동작해서 넘어갔는데 왜 자동 주입이 되지 않았는지 궁금해서 원인을 찾아보았습니다.
자료 조사 결과, 해당 오류를 잡기 위해선 해당 객체에 Bean을 수동으로 주입해야한다고 합니다. 즉, @Configuration 어노테이션을 활용하여 위의 객체들에 Bean을 수동으로 주입하는 과정을 추가해야 합니다. @Configuration 어노테이션은 @ComponentScan이 처리될 때 자기 자신과 이 클래스에 @Bean으로 설정된 모든 객체의 초기화를 진행하여 해당 객체를 사용 시 Bean이 주입됩니다.
package com.example.test.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
@EnableJdbcRepositories
public class JdbcConfig extends AbstractJdbcConfiguration {
@Value("${spring.datasource.driverClassName}")
public String driverClassName;
@Value("${spring.datasource.url}")
public String url;
@Value("${spring.datasource.username}")
public String username;
@Value("${spring.datasource.password}")
public String password;
// 접근할 DB 정의
@Bean
public DataSource dataSource() {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName(driverClassName);
dataSourceBuilder.url(url);
dataSourceBuilder.username(username);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
// 사용할 JdbcTemplate에 대해서 정의 진행
@Bean
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource());
}
}
따라서 공식 문서와 다른 블로그들을 통해 JdbcConfig 클래스를 생성했습니다. 우선 Datasource 객체를 이용하여 application.properties 내에 존재하는 DB 설정값을을 가져와 접근할 DB 정보를 매핑합니다. 이 후 JdbcTemplate 객체를 생성 후 해당 Datasource 객체를 파라미터로 넣어 리턴합니다. 이 때 각 객체 위에 @Bean 어노테이션을 붙이고 @Configuration 어노테이션과 JDBC 리포지토리에 접근 가능하도록 하는 @EnableJdbcRepositories 어노테이션도 같이 추가합니다.
그 결과 이전에 발생했던 오류가 발생하지 않는 것을 확인할 수 있습니다.
테스트 진행 시 정상적으로 잘 작동합니다.
package com.example.test.controller;
import com.example.test.model.request.InsertUserRequestDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ExtendWith(SpringExtension.class)
//@ContextConfiguration(classes = SecurityConfig.class)
@WebAppConfiguration
@SpringBootTest
class UserControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@BeforeEach
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
// .apply(springSecurity())
.build();
}
@Test
public void getUserInfoTest() throws Exception{
mvc.perform(get("/user/1"))
.andExpect(status().isOk());
}
}
다음 코드는 MockMvc 객체에 Bean 주입을 위한 코드 수정입니다. Spring Security 공식 홈페이지의 코드를 수정한 것으로 핵심적인 부분은 기존의 @AutoConfigureMockMvc 어노테이션을 통해 MockMvc 객체에 @Autowired를 하여 Bean을 직접 주입한 방식에서 @WebAppConfiguration 어노테이션을 이용하여 WebApplicationContext 객체를 @Autowired한 후 MockMvc 객체를 만들고 setup 메소드를 이용하여 WebApplicationContext 값을 추가해 빌드합니다. 주석 처리한 부분을 해제하면 Spring Security에서 사용 가능하다고 하는데 이 부분은 다음 포스팅 때 같이 설명드리겠습니다.
공식 문서에 MockMvcBuilder 설명을 보면 DispathcerServlet이 WebApplicationContext를 사용하여 Infrastructure와 application controller를 검색합니다. 따라서 현재 application controller의 정보를 MockMvc 객체에 추가하여 빌드하기 때문에 정상적으로 Bean 객체가 주입될 것이라고 유추해볼 수 있습니다.
이를 통해 Bean 자동 주입 오류가 발생하지 않는 것을 확인할 수 있으며
테스트 역시 성공적으로 통과했습니다. 그럼 이상으로 오늘의 포스팅 마치도록 하겠습니다!