Spring on Hibernate


一つ前のエントリーではHibernate単体だったが、Spring上で動かしてみる。

以下を使用するため、入手してライブラリをクラスパスに追加しておく。
http://commons.apache.org/dbcp/ から commons-dbcp-1.2.2.zip
http://commons.apache.org/pool/ から commons-pool-1.5.2-bin.zip


ソースフォルダのルートに applicationContext.xml のファイルを用意。テンプレートは以下。beans タグ内に設定を追加していく。

<?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-2.5.xsd">

</beans>

applicationContext.xml にデータソースの定義を追加

  <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="url" value="jdbc:h2:tcp://localhost:9092/spring"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
  </bean>


同様に applicationContext.xml の SessionFactory の Bean 定義を追加

  <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="hibernateProperties">
      <value>
		hibernate.dialect = org.hibernate.dialect.H2Dialect
		hibernate.show_sql = true
		hibernate.format_sql = true
		hibernate.hbm2ddl.auto = create
      </value>
    </property>
    <property name="annotatedClasses">
     <list><value>etc9.domain.entity.Product</value></list>
    </property>
    <property name="annotatedPackages">
     <list><value>etc9.domain.entity</value></list>
    </property>
  </bean>

この後に作成するBeanの定義も加えておく。

  <bean id="productService" class="etc9.domain.ProductService">
    <property name="productDao" ref="productDao"/>
  </bean>

  <bean id="productDao" class="etc9.dao.ProductDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
  </bean>


Entityから作成。

package etc9.domain.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Product {
    private Long id;
    private String name;
    private String category;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
}


Dao用のインターフェースを作成。

package etc9.dao;

import java.util.Collection;
import org.springframework.dao.DataAccessException;
import etc9.domain.entity.Product;

public interface ProductDao {
    Collection<Product> findByCategory(final String category) throws DataAccessException;
    Product get(Long id);
    Product save(Product product);
}

Implは、

package etc9.dao;

import java.sql.SQLException;
import java.util.Collection;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import etc9.domain.entity.Product;

public class ProductDaoImpl implements ProductDao {
    private HibernateTemplate hibernateTemplate;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public Collection<Product> findByCategory(final String category) throws DataAccessException {
        return (Collection<Product>) this.hibernateTemplate.execute(new HibernateCallback(){
            @Override public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(Product.class);
                criteria.add(Restrictions.eq("category", category));
                criteria.setMaxResults(6);
                return criteria.list();
            }});
    }
    @Override public Product get(final Long id) {
        return (Product) this.hibernateTemplate.get(Product.class, id);
    }
    @Override public Product save(final Product product) {
        this.hibernateTemplate.save(product);
        return product;
    }
}


Daoを利用するサービスを作成。

package etc9.domain;

import etc9.dao.ProductDao;
import etc9.domain.entity.Product;

public class ProductService {
    private ProductDao productDao;
    
    public void setproductDao(ProductDao productDao) {
        this.productDao = productDao;
    }
    
    public Collection<Product> exec() {
        Product p1 = new Product();
        p1.setCategory("category");
        p1.setName("name1");
        this.productDao.save(p1);
		
        return this.productDao.findByCategory("category");
    }
}


テストケース。

package etc9;

import org.h2.tools.Server;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;

import etc9.domain.ProductService;

public class Test {
    private static final String BASE_DIR = "db\\h2";
    private static Server tcpServer;

    @BeforeSuite
    public void beforeSuite() throws Exception {
        tcpServer = org.h2.tools.Server.createTcpServer(
                new String[] { "-baseDir", BASE_DIR, "-tcpPort", "9092" }).start();
        
    }
    @AfterSuite
    public void afterSuite() {
        tcpServer.shutdown();
    }
    
    @org.testng.annotations.Test
    public void test() {
        ApplicationContext context
            = new ClassPathXmlApplicationContext("applicationContext.xml");
        ProductService service
            = (ProductService)context.getBean("productService");
        service.exec();
    }
}

Autowired化する

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <context:annotation-config/> 

DI対象のメソッドに@Autowiredアノテーションを付ける。
ProductDaoImplに以下の変更を行う。

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

ProductServiceに以下の変更を行う。

    @Autowired
    public void setproductDao(ProductDao productDao) {
        this.productDao = productDao;
    }

applicationContext.xmlの各Bean定義は以下のように簡略化できる。

  <bean id="productService" class="etc9.domain.ProductService">
  </bean>

  <bean id="productDao" class="etc9.dao.ProductDaoImpl">
  </bean>