잊지 않겠습니다.

'SLF4j'에 해당되는 글 1건

  1. 2012.11.19 Spring 3.1 + Hibernate 설정 및 테스트 (2)

구성된 project는 아주 기본적인 Hibernate를 이용한 ORM 구성을 가지게 된다. 

추가로, Transaction과 Connection Polling을 구성하도록 한다. 


1. Transaction의 추가


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-tx</artifactId>

<version>3.1.2.RELEASE</version>

</dependency>


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</artifactId>

<version>3.1.2.RELEASE</version>

</dependency>


spring trasaction을 위한 jar와 aop를 위한 jar를 추가한다.

생성된 PersonService의 interface를 선언한다. 

public interface IPersonService {
Person add(String firstName, String lastName, Double money);
List<Person> getAll();
Person get(Integer id);
Person edit(Integer id, String firstName, String lastName, Double money);
void delete(Integer id);
}

PersonService에 interface구현을 추가하고, @Transaction annotation을 붙인다. 
구현된 PersonService는 다음과 같다.

@Service("personService")
@Transactional
public class PersonService implements IPersonService {
@Resource
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
public List<Person> getAll() {
Session session = sessionFactory.getCurrentSession();
List<Person> persons = (List<Person>) session.createCriteria(Person.class).list();
return persons;
}
public Person get(Integer id) {
Session session = sessionFactory.getCurrentSession();
return (Person) session.get(Person.class, id);
}
public Person add(String firstName, String lastName, Double money) {
Person person = new Person();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setMoney(money);
Session session = sessionFactory.getCurrentSession();
session.save(person);
return person;
}
public Person edit(Integer id, String firstName, String lastName, Double money) {
Person person = get(id);
Session session = sessionFactory.getCurrentSession();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setMoney(money);
session.update(person);
return person;
}
public void delete(Integer id) {
Person person = get(id);
Session session = sessionFactory.getCurrentSession();
session.delete(person);
}
}

위 코드와 기존코드의 가장 큰 차이는 sessionFactory.getCurrentSession()이다. 기존 코드는 sessionFactory.openSession()을 사용하지만, transaction을 사용하는 Service는 sessionFactory.getCurrentSession()이 된다. 그 이유는 다음과 같다. 

Transaction annotation을 사용하는 경우에 annotation에 의해서 다음과 같은 코드로 변경이 되어서 실행이 되는것과 동일해진다. 


public Person edit(Integer id, String firstName, String lastName, Double money) {

Session s = sessionFactory.openSession();
Transaction transaction = s.beginTransaction();

Person person = get(id);
Session session = sessionFactory.getCurrentSession();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setMoney(money);
session.update(person);

transaction.commit();
return person;
}

Transaction AOP에 의해서 항시 openSession, beginTransaction 이 실행되는것과 동일하게 구성이 되게 된다. 그리고, method의 종료시에 transaction의 commit가 자동으로 이루어지기 때문에 Transaction이 구현되는 서비스에서는 sessionFactory에서 getCurrentSession을 통해서 transaction이 적용된 session을 얻어내야지된다.

마지막으로 spring bean annotation설정을 위해서 spring-context.xml에 다음과 같은 내용을 추가하도록 한다.
<!-- sessionFactory에 transaction 구성 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" 
                         p:sessionFactory-ref="sessionFactory" />
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- sessionFactory 구성 -->

테스트를 구동하고, 정상적으로 동작하는지 확인한다. 



2. Connection Pool의 추가


hibernate에서 주로 사용하는 c3p0를 connection pool로 사용하도록 한다. c3p0는 사용하기 쉽고, 가벼워서 WAS에서 제공하는 connection pool을 사용하지 않는 경우에 주로 추천되는 connection pool이다. 


c3p0 dependency를 pom.xml에 다음과 같이 추가한다.


<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-c3p0</artifactId>

<version>4.1.7.Final</version>

</dependency>



spring-context에서 기존 dataSource를 제거하고 c3p0에서 제공하는 Pooling DataSource로 대체한다. 

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close"
p:driverClass="${app.jdbc.driverClassName}"
p:jdbcUrl="${app.jdbc.url}"
p:user="${app.jdbc.username}"
p:password="${app.jdbc.password}"
p:acquireIncrement="5"
p:idleConnectionTestPeriod="60"
p:maxPoolSize="10"
p:maxStatements="50"
p:minPoolSize="5"/>


테스트를 구동하고, 정상적으로 테스트를 통과하면 완료된다.


일단, 기본 WEB Application을 개발할 수 있는 환경을 만들었지만, 하나 빼먹은 것이 계속해서보인다.; 

그것은 바로... Log!!! 


3. Log의 추가


요즘 java의 추세인 logback와 slf4j를 사용하도록 한다.; 일단 log4j보다 속도가 좋고, 거기에 log4j와 동일한 방법으로 사용이 가능하다는 장점때문에 logback를 slf4j를 이용해서 facade pattern으로 사용하게 된다. 


pom.xml에 다음을 추가한다. 

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

<version>${slf4j.version}</version>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>${logback.version}</version>

</dependency>


<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-core</artifactId>

<version>${logback.version}</version>

</dependency>


그리고,  resource에 logback.xml 파일을 추가하도록 한다. logback.xml은 기본적으로 logback이 사용될때, 기본적으로 load 되는 설정 xml이다. 주로 사용하는 RollingFileAppender를 이용해서 구성하도록 한다. 


logback의 Appender의 종류와 사용법들은 다음 site에서 참고하도록 한다.

http://logback.qos.ch/manual/appenders.html



<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n

</pattern>

</encoder>

</appender>

<appender name="FILEOUT" class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>c:\\Logs\\BackLog\\logFile.log</file>

<maxHistory>30</maxHistory>

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>c:\\Logs\\BackLog\\logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

<maxHistory>30</maxHistory>

</rollingPolicy>

<encoder>

<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n

</pattern>

</encoder>

</appender>

<root level="INFO">

<appender-ref ref="STDOUT" />

<appender-ref ref="FILEOUT" />

</root>

</configuration>



이제 test를 실행하면 Console과 LogFile이 정상적으로 만들어지는 것이 확인된다. 이로서 개발전 기본 설정은 모두 마쳐지게 된다. 



Posted by Y2K
,