新公司有自己的一套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來測試囉。
1 則留言:
收下了, 寫得很好
張貼留言