新公司有自己的一套Framework,並自行開發一套code gen的工具,稍為喚起了我曽經用過Hibernate Tools的記憶,一方面是因為用了JDK5的Generic後,要寫的Code變少,另一方面也是因為如果有修改,code gen出來的東西比較不易配合更動,所以也沒有納入我常用的工具之一。不過既然想起了Hibernate tools,那就再用用看有沒有什麼改變,或許會有驚喜吧。
不過似乎沒有…特別是不能直接用Spring Configuration Xml中已經訂好的設定,一定要另訂hibernate.cfg.xml,這就又讓我難過了一下,再發現居然連hibernate3-maven-plugin也無法直接使用Spring 裡訂好的AnnotationSessionFactoryBean或LocalSessionFactoryBean,只好試著改看看有沒有辦法可以讓我懶一點不要再去重訂hibernate.cfg.xml。
發現hibernate3-maven-plugin中有一個AnnotationComponentConfiguration,看來似是一個不錯的切入點,稍為改了一下還發現真能work!下面列的就是實做出來的東西。
1.pom.xml
改maven的plugin不用maven也太說不過去了吧,所以pom.xml是一定要的。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.elliot.hibernate</groupId>
<artifactId>maven-hibernate3-jdk15</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hibernate3 Implementation - JDK15</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.codehaus.mojo.hibernate3</groupId>
<artifactId>maven-hibernate3-jdk15</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.3.2.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>1.0.2.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-common</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.4.GA</version>
</dependency>
<!--可視情形改用其他版本的Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>3.0.0.RC1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. SpringComponentConfiguration.java
我暫用org.codehaus.mojo.hibernate3.configuration這package,怕AnnotationComponentConfiguration會不會有什麼method不能用,後來看code發現沒問題,也可以改成你喜歡的名稱
package org.codehaus.mojo.hibernate3.configuration;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.mojo.hibernate3.ExporterMojo;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.util.StringUtils;
public class SpringComponentConfiguration extends
AnnotationComponentConfiguration {
private static final Log logger = LogFactory
.getLog(SpringComponentConfiguration.class);
private ExporterMojo exporterMojo;
private ApplicationContext applicationContext;
public String getName() {
return "springconfiguration";
}
public ExporterMojo getExporterMojo() {
return exporterMojo;
}
public void setExporterMojo(ExporterMojo exporterMojo) {
this.exporterMojo = exporterMojo;
}
@Override
protected Configuration createConfiguration() {
String sessionFactoryBean = getExporterMojo().getComponentProperty(
"sessionFactoryBean", "sessionFactory");
String appContextLocations = getExporterMojo().getComponentProperty(
"appContextLocations", "classpath*:spring*.xml");
logger.info("Initial info: [sessionFactoryBean]=" + sessionFactoryBean
+ ", [appContextLocations]=" + appContextLocations);
String[] locations = StringUtils.delimitedListToStringArray(
appContextLocations, ",");
// Initial ApplicationContext from spring configuration xml files.
this.applicationContext = new FileSystemXmlApplicationContext(locations);
// Get AnnotationSessionFactoryBean from spring
AnnotationSessionFactoryBean asfb = (AnnotationSessionFactoryBean) applicationContext
.getBean("&" + sessionFactoryBean);
DataSource dataSource = asfb.getDataSource();
ThreadLocalHolder.setDataSource(dataSource);
Configuration configuration = asfb.getConfiguration();
configuration.setProperty(Environment.CONNECTION_PROVIDER,
ThreadLocalConnectionProvider.class.getName());
return configuration;
}
@Override
protected void validateParameters() throws MojoExecutionException {
// don't validate
}
}
3.ThreadLocalConnectionProvider.java
因為Configuration不能直接設DataSource,所以只好放到ThreadLocal
package org.codehaus.mojo.hibernate3.configuration;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
public class ThreadLocalConnectionProvider implements ConnectionProvider {
private static final Log logger = LogFactory.getLog(ThreadLocalConnectionProvider.class);
public ThreadLocalConnectionProvider() {
}
public void close() throws HibernateException {
}
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
public void configure(Properties props) throws HibernateException {
//Do nothing
}
public Connection getConnection() throws SQLException {
DataSource dataSource = ThreadLocalHolder.getDataSource();
if (null == dataSource) {
logger.error("Please check ThreadLocalHolder.setDataSource has been invocked.");
throw new SQLException("No usable DataSource.");
}
return dataSource.getConnection();
}
public boolean supportsAggressiveRelease() {
// TODO Auto-generated method stub
return true;
}
}
4.ThreadLocalHolder.java
package org.codehaus.mojo.hibernate3.configuration;
import javax.sql.DataSource;
public abstract class ThreadLocalHolder {
private static ThreadLocal<DataSource> dataSourceHolder = new ThreadLocal<DataSource>();
public static DataSource getDataSource() {
return dataSourceHolder.get();
}
public static void setDataSource(DataSource dataSource) {
dataSourceHolder.set(dataSource);
}
}
5.components.xml
這檔案放在src/main/resources/META-INF/plexus下,是maven plugin的設定檔
<component-set>
<components>
<component>
<role>org.codehaus.mojo.hibernate3.configuration.ComponentConfiguration</role>
<role-hint>springconfiguration</role-hint>
<implementation>org.codehaus.mojo.hibernate3.configuration.SpringComponentConfiguration</implementation>
</component>
</components>
</component-set>
完成之後就用mvn install裝到repository裡以供使用,使用方式就只是改變hibernate3-maven-plugin中的dependency。
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<componentProperties>
<jdk5>true</jdk5>
<implementation>springconfiguration</implementation>
<appContextLocations>classpath*:applicationContext.xml</appContextLocations>
<sessionFactoryBean>sessionFactory</sessionFactoryBean>
</componentProperties>
</configuration>
<dependencies>
<dependency>
<groupId>org.elliot.hibernate</groupId>
<artifactId>maven-hibernate3-jdk15</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.3.2.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.121</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
加入configuration中列出的設定,appContextLocations是專案中spring設定檔的檔案位置,sessionFactoryBean則是spring中你定義的AnnotationSessionFactoryBean名稱。
再來就可以用mvn hibernate3:hbm2ddl 之類的goals來測試囉。