import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
public class StudentDAOImpl implements StudentDAO {
private JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
public DataSource getDataSource() {
String url = "jdbc:mysql://localhost:3306/School";
String username = "사용자이름";
String password = "비밀번호";
DataSource dataSource = new DriverManagerDataSource(url, username, password);
return dataSource;
}
@Override
public void insert(Student student) {
String sql = "INSERT INTO STUDENT VALUES (?, ?, ?)";
Object[] arg = {student.getRole_no(), student.getName(), student.getAddress()};
int noOfRowInserted = jdbcTemplate.update(sql, arg);
System.out.println("No of row inserted is "+noOfRowInserted);
}
}
이전 글에서 작성한 StudentDAOImpl 코드는 표준 방식이 아닙니다. 왜냐하면 우리가 직접 new 연산자를 이용하여 JdbcTemplate과 DataSource를 생성하고 있기 때문입니다. 이것은 스프링이 해야할 일입니다.
Spring Configuration XML 파일을 생성하면서 이름을 beans.xml
라고 지어줍니다.
위와 같은 방식으로 jdbc, context 네임스페이스를 추가합니다.
StudentDAOImpl 클래스에서 DriverMangerDataSource 클래스의 Reference를 복사합니다.
beans.xml에 <bean>
을 추가하고 클래스 이름으로 복사한 Reference를 붙여넣기 합니다.
id로는 "dataSource"라고 지정했습니다. xml에 DriverManagerDataSource 빈 객체를 추가했으니, StudentDAOImpl 클래스에서 url, username, password를 인수로 제공했던 것을 xml에도 구현하기로 합니다.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<constructor-arg name="url" value="jdbc:mysql://localhost:3306/School" />
<constructor-arg name="username" value="사용자이름" />
<constructor-arg name="password" value="비밀번호" />
</bean>
위와 같이 getDataSource 함수의 주요 내용을 빈 에 옮겼다면 StudentDAOImpl 클래스에서 해당 함수를 삭제합니다.
JdbcTemplate 또한 빈 객체로 만들기 위해 Reference를 복사합니다.
<bean id="jdbcTemplateObject" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
JdbcTemplate을 초기화하기 위해 DataSource 인스턴스가 필요했고, 그것을 빈 객체로 구현한 상태이기 때문에 ref
로 dataSource 빈을 전달합니다.
beans.xml에 구현하여 필요 없어진 부분을 코드에서 삭제했습니다.
하지만, 이 StudentDAOImpl 클래스 또한 우리가 직접 구현할 필요는 없는 것입니다. 이것 역시 스프링이 구현해야 하는 부분이며 하드 코딩 해서는 안됩니다.
앞서와 같은 방법으로 StudentDAOImpl 빈 객체를 생성합니다. 하지만 이 빈 객체는 특이한 점이 있습니다. 바로 JdbcTemplate을 프로퍼티로 가지고 있는 점, 즉 의존성으로 주입 당하고 있는 점인데요, 이것을 beans.xml에 옮기는 방식은 두가지가 있습니다. setter 메서드를 통해서 또는 constructor 방식을 통해서 주입시킬 수 있습니다. 이번에는 setter를 사용해보도록 합니다.
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
setter 메서드를 추가하고 beans.xml에서 아래와 같이 해당 내용을 작성합니다.
<bean id="studentDao" class="tutorial.schooljdbc.StudentDAOImpl">
<property name="jdbcTemplate" ref="jdbcTemplateObject"> </property>
</bean>
property로 jdbcTemplate을 의존성으로 추가하고 ref로 앞서 구현한 jdbcTemplateObject 빈을 전달합니다.
StudentDAO 객체를 스프링 ApplicationContext으로부터 가져오겠습니다.
우선 ApplicationContext 에는 스프링 빈 객체들이 들어있는데, 우리는 classpath로 application context를 로드할 것이므로 ClassPathXmlApplicationContext를 사용합니다.
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Populate {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("application context loaded.. ");
StudentDAOImpl studentDAOImpl = context.getBean("studentDao", StudentDAOImpl.class);
Student student_A = new Student();
student_A.setRole_no(2);
student_A.setName("Choi");
student_A.setAddress("Busan");
studentDAOImpl.insert(student_A);
// StudentDAO studentDAO = new StudentDAOImpl();
// studentDAO.insert(student_A);
}
}
"beans.xml"은 스프링 컨테이너에게 빈(Bean) 구성 정보를 제공합니다. "beans.xml" 파일에서 정의된 빈 중에서 studentDao라는 이름의 빈을 가져와서 StudentDAOImpl 타입으로 캐스팅하여 studentDAOImpl 변수에 할당합니다. 스프링의 핵심 기능 중 하나는 이러한 객체 생성과 관리를 컨테이너에 위임하여 의존성 주입(Dependency Injection)을 통해 코드를 더 유연하게 만드는 것입니다.
src 디렉터리에 있는 java 코드 외에 xml을 읽어들이지 못하기 때문에 resources 디렉터리로 옮겨야 성공적으로 실행됩니다.
방금 실행한 코드로 인해 테이블에 새로운 레이블이 추가된 것을 확인할 수 있습니다.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<constructor-arg name="url" value="jdbc:mysql://localhost:3306/School" />
<constructor-arg name="username" value="사용자이름" />
<constructor-arg name="password" value="비밀번호" />
</bean>
앞서 jdbcTemplateObject 빈 객체를 studentDao 빈의 의존성으로 주입할 때 StudentDaoImpl 클래스에 jdbcTemplate의 속성 값을 할당하는 setter 메서드를 추가했듯이, 이번에는 dataSource 빈 객체를 생성자 주입 방식에서 setter 주입 방식으로 변경해보기로 합니다.
DriverManagerDataSource 는 AbstractDriverBasedDataSource를 확장하고 있는데, 우리가 생성자 주입 방식에서 활용했던 url, username, password를 속성으로 가지고 있습니다. DriverManagerDataSource가 AbstractDriverBasedDataSource를 확장하고 있으므로 이미 이 속성을 가지고 있는 것입니다. 그래서 추가로 코드를 입력할 필요 없이 xml 파일을 아래와 같이 수정할 수 있습니다.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/School" />
<property name="username" value="사용자이름" />
<property name="password" value="비밀번호" />
</bean>
xml 파일을 수정 후에도 다른 데이터를 테이블에 추가하는 데 성공했습니다.
외부라이브러리에 추가했던 connector-j의 디렉터리들을 살펴보면 Driver 클래스를 어디에 가지고 있는지 경로를 추적할 수 있습니다.
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/School" />
<property name="username" value="hammy" />
<property name="password" value="ji2366" />
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
</bean>
driverClassName 이라는 이름을 가진 속성에 경로를 값으로 제공합니다.
스프링 JDBC의 DriverManagerDataSource
클래스는 driverClassName
속성을 지정하지 않고도 데이터베이스 연결을 수행할 수 있습니다. 이 클래스는 주어진 JDBC URL에서 드라이버를 추론하여 자동으로 드라이버를 로드하고 데이터베이스 연결을 수행합니다.
만약 데이터베이스의 JDBC 드라이버가 클래스 패스에 포함되어 있고, JDBC URL이 드라이버의 이름을 명시하고 있다면, 스프링 JDBC는 자동으로 해당 드라이버를 로드하여 사용합니다.
하지만 명시적으로 driverClassName
을 지정하는 것은 코드의 가독성을 높이고 명시적으로 사용하는 데이터베이스의 드라이버를 알려줄 수 있어서 추천되는 방법입니다. 또한, 애플리케이션이 다른 환경에서 실행될 때도 안정적으로 동작하도록 도와줍니다.