지금의 코드는 각각의 의존성을 모두 클래스가 직접 관리하고 있다.
그러나, 결국 스프링이 제공하는 AOP등을 사용하기 위해서는 우리의 클래스를 스프링 빈으로 등록해 두어야 할 것이고, 빈으로 등록하는 김에 스프링이 직접 의존성을 관리해 주는 것이 좋을 것 같다는 생각이 들었다.
스프링에게 의존성을 주입 받도록 코드를 수정해 주자.
수동으로 의존성 설정
applicationContext.xml
스프링에 수동으로 빈을 등록하고, 의존성 관계를 주입하기 위해서 xml 파일에 의존성을 명시해 두도록 하자.
applicationContext.xml의 위치는 main > resource 바로 아래에 두었다.
다음은 applicationContext.xml의 전문이다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="DAOContext" class="com.example.selfmadeBlog.DAO.DAOContext"/>
<bean id="postingDAO" class = "com.example.selfmadeBlog.DAO.PostingDAO">
<property name="daoContext" ref="DAOContext"/>
</bean>
<bean id="userDAO" class="com.example.selfmadeBlog.DAO.UserDAO">
<property name="daoContext" ref="DAOContext"/>
</bean>
</beans>
다음과 같이 각 클래스들을 빈으로 등록해 두고, 의존성 주입을 위해 `<property>` 태그를 사용했다.
위와 같은 의존성 주입에는 setter가 사용될 것이기 때문에 `PostingDAO`와 `UserDAO`에 `setDAOContext` 메서드를 생성해 주자.
추가적으로, 스프링에서 빈으로 등록하기 위한 모든 클래스들은 기본 생성자를 가지고 있어야 한다.
이전 코드에서 싱글톤으로 객체를 관리하기 위해 `private`으로 설정해 두었던 기본생성자를 `public`으로 만들어 주거나, 모든 생성자를 전부 지워주자.
public class PostingDAO {
private DAOContext daoContext;
public void setDaoContext(DAOContext daoContext) {
this.daoContext = daoContext;
}
}
마지막으로, 테스트코드에서도 해당 스프링 빈을 가지고 와야 테스트를 진행할 수 있다.
테스트코드에서는 `ApplicationContext` 객체를 하나 생성해서, 등록되어 있는 빈을 가져 올 것이다.
@ExtendWith(SpringExtension.class)
class PostingDAOTest {
ApplicationContext context = new
ClassPathXmlApplicationContext("/applicationContext.xml");
UserDAO userDAO = context.getBean(UserDAO.class);
PostingDAO postingDAO = context.getBean(PostingDAO.class);
//...
위와 같이 등록된 스프링 빈을 가져온 후, 테스트코드를 실행해 보자.
테스트 결과는 성공이다!
자동으로 의존성 주입
그런데, 우리가 의존성 관계를 명시하지 않아도 스프링은 알아서 적절한 클래스를 찾아서 의존성을 주입해 줄 수 있다.
`@Autowired`를 사용해서 의존성을 주입해 보자.
이제 설정 파일은 사용하지 않을 것이기 때문에 `applicationContext.xml` 파일은 삭제해 준다.
가장 먼저, 의존성 주입을 받을 클래스와 의존성 주입에 사용될 클래스 모두 스프링 빈으로 등록해 두어야 한다.
모두 DB에 접근하기 위한 클래스이니 `@Repository` 어노테이션을 사용해 등록해 준다.
그리고 `DAOContext` 클래스를 사용할 두 개의 DAO 클래스 내부의 `DAOContext` 필드에는 `@Autowired`를 붙여준다.
@Repository
public class DAOContext{/*...*/}
@Repository
public class PostingDAO{
@Autowired
private DAOContext daoContext;
/*...*/
}
@Repository
public class UserDAO{
@Autowired
private DAOContext daoContext;
/*...*/
}
테스트코드에서도 `UserDAO`, `PostingDAO`와 같은 빈들을 주입 받아야 해당 클래스에 구현되어 있는 로직들을 테스트 해 볼 수 있다.
그런데, 해당 빈들이 생성되어 있는 곳은 `main` 패키지이고, 테스트 클래스들은 `test` 패키지에 생성된다.
때문에 테스트클래스에서는 의존성 주입을 위해 다음과 같이 작성해 주어야 한다.
@SpringBootTest
@SpringJUnitConfig(classes = SelfmadeBlogApplication.class)
class PostingDAOTest {
@Autowired
UserDAO userDAO;
@Autowired
PostingDAO postingDAO;
//...//
}
`@SpringJUnitConfig(classes = SelfmadeBlogApplication.class)`를 사용해 메인 어플리케이션 클래스의 경로에 있는 빈들을 주입할 수 있게 되는 것이다.
아래 포스팅들의 도움을 받았다.
https://cseella.tistory.com/184
이제 테스트를 실행해 보자.
테스트 실패
테스트가 실패한다...!
스택 트레이스를 살펴보자.
java.lang.IllegalStateException:
Failed to load ApplicationContext for ...
at
//...
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dataSource' defined
in class path resource [...] : Failed to instantiate
[...] : Factory method 'dataSource' threw exception with
message: Failed to determine a suitable driver class
at
//...
Caused by: org.springframework.beans.BeanInstantiationException:
Failed to instantiate [...]:
Factory method 'dataSource' threw exception with message:
Failed to determine a suitable driver class
at
... 110 more
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
$DataSourceBeanCreationException: Failed to determine a suitable driver class
at app//org.springframework.boot.autoconfigure.jdbc.DataSourceProp
... 111 more
간단히 말하자면, `dataSource` 빈을 생성하지 못한다는 것이다.
분명 나는 `dataSource` 라는 빈을 정의해 준 적도, 사용한 적도 없는데 왜 이런 오류가 생기는 것일까?
스프링부트의 dataSource 빈 자동 등록
우리는 JDBC를 사용하기 위해 gradle에 다음과 같은 의존성을 추가해 주었다.
//db connect
implementation('mysql:mysql-connector-java:8.0.33')
이 때 스프링부트는 자동으로 데이터의 커넥션 풀 관리 등의 기능을 제공하는 `dataSource` 라는 이름의 빈을 등록한다. 이 때 스프링은 `application.properties`에 있는 설정을 기본으로 빈을 생성한다.
테스트 코드의 `@SpringBootTest`
스프링부트는 `@SpringBootTest` 어노테이션을 사용한 테스트 클래스를 실행시키면 통합테스트를 위한 환경을 만들어 준다.
모든 빈을 스캔하고, 어플리케이션 컨텍스트를 생성하는데 이 때 자동으로 `dataSource` 빈을 생성한다.
자동으로 `dataSource` 빈을 생성하지 않게 하려면 다음의 방법들을 사용할 수 있다.
1. 테스트코드에 자동 설정 제외하기
@ExtendWith(SpringExtension.class)
@SpringBootTest
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
@SpringJUnitConfig(classes = SelfmadeBlogApplication.class)
class PostingDAOTest { /*...*/ }
`@EnableAutoConfiguration`으로 `dataSource`의 자동 설정을 제외해 `dataSource` 빈을 생성하지 않을 수 있다.
2. 메인 어플리케이션 클래스에서 자동 설정 제외하기
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class SelfmadeBlogApplication { /*...*/ }
같은 설정을 메인 클래스에서 설정해 주어도 된다.
그러나, 나중에 리팩토링을 하면서 언젠가 사용하게 될 빈이니 이왕이면 제대로 된 설정으로 생성해 두자.
`application.property`
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/selfmadeblog
spring.datasource.username=root
spring.datasource.password=111111
\
다시 테스트가 성공한다!!
도움 받은 문서들
https://recordsoflife.tistory.com/1431
https://mangkyu.tistory.com/242
https://prolog.techcourse.co.kr/studylogs/2445
https://ksh-coding.tistory.com/88
'프로젝트 > selfmade Blog - V1 (deprecated)' 카테고리의 다른 글
6. 유저 CRUD 구현 및 테스트 데이터 삭제 (0) | 2023.08.13 |
---|---|
5. 블로그 글 수정, 삭제 기능 (0) | 2023.08.13 |
3. 블로그 글 작성 기능 - 조회 기능 및 중복 Context 추출 (0) | 2023.08.11 |
3. 블로그 글 작성 기능 - 글 생성 및 중복 Context 추출 (1) | 2023.08.11 |
2. JDBC를 이용한 DB 설정 (0) | 2023.08.11 |
댓글