`
cats_tiger
  • 浏览: 276489 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一劳永逸——让Spring自动加载Hibernate Annotated Classes

阅读更多
通常,spring整合Hibernate的SessionFactory是这样做的:
<property name="annotatedClasses">
   <list><value>com.systop.common.core.dao.testmodel.TestDept</value></list>
</property>
<property name="mappingLocations">
     <list><value>classpath*:org/jbpm/**/*.hbm.xml</value></list>
</property>

Spring可以根据mappingLocations属性中定义的Path Pattern自动加载hbm文件,但是对于annotatedClasses则只能一个一个的苦恼的写上去。无论是Hibernate还是Spring,都不能自动的加载某个package下的Anntated Classes。这样,一旦项目需要重构或者增加/减少Tables就会带来一些麻烦。尤其是对于那些已经打包的应用来说更是如此。
能不能让Spring自动加载AnnotatedClasses呢,我想到了Spring2.5中component-scan,于是便照猫画虎的写了一个AnnotationSessionFactoryBean的子类:
package com.systop.common.core.dao.hibernate;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;

import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternCompiler;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.hibernate.HibernateException;
import org.hibernate.cfg.AnnotationConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

import com.systop.common.core.exception.ApplicationException;

@SuppressWarnings("unchecked")
public class AnnotationSessionFactoryBeanEx extends AnnotationSessionFactoryBean {
  private static final Logger logger = LoggerFactory
      .getLogger(AnnotationSessionFactoryBeanEx.class);

  /**
   * The locations of the hibernate enity class files. They are often some of the string with
   * Sping-style resource. A ".class" subfix can make the scaning more precise.
   * <p> example:
   * <pre>
   * classpath*:com/systop/** /model/*.class
   * </pre>
   */
  private String[] annotatedClassesLocations;

  /**
   * Which classes are not included in the session.
   * They are some of the regular expression.
   */
  private String[] excludedClassesRegexPatterns;  

  /**
   * @param annotatedClassesLocations the annotatedClassesLocations to set
   */
  public void setAnnotatedClassesLocations(String[] annotatedClassesLocations) {
    this.annotatedClassesLocations = annotatedClassesLocations;
  }

  /**
   * @see AnnotationSessionFactoryBean#postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration)
   */
  @Override
  protected void postProcessAnnotationConfiguration(AnnotationConfiguration config)
      throws HibernateException {
    Set<Class> annClasses = scanAnnotatedClasses(); //Scan enity classes.
    // Add entity classes to the configuration.
    if (!CollectionUtils.isEmpty(annClasses)) {
      for (Class annClass : annClasses) {
        config.addAnnotatedClass(annClass);
      }
    }
  }
  
  /**
   * Scan annotated hibernate classes in the locations.
   * @return Set of the annotated classes, if no matched class, return empty Set.
   */
  private Set<Class> scanAnnotatedClasses() {
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
        resourcePatternResolver);
    Set<Class> annotatedClasses = new HashSet<Class>();
    if (annotatedClassesLocations != null) {
      try {
        for (String annClassesLocation : annotatedClassesLocations) {
          //Resolve the resources
          Resource[] resources = resourcePatternResolver.getResources(annClassesLocation);
          for (Resource resource : resources) {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            String className = metadataReader.getClassMetadata().getClassName();
            //If the class is hibernate enity class, and it does not match the excluded class patterns.
            if (isEntityClass(metadataReader) && !isExcludedClass(className)) {
              Class clazz = ClassUtils.forName(className);
              annotatedClasses.add(clazz);
              logger.debug("A entity class has been found. \n({})", clazz.getName());
            }
          }

        }
      } catch (IOException e) {
        logger.error("I/O failure during classpath scanning, ({})", e.getMessage());
        e.printStackTrace();
        throw new ApplicationException(e);
      } catch (ClassNotFoundException e) {
        logger.error("Class not found, ({})", e.getMessage());
        e.printStackTrace();
        throw new ApplicationException(e);
      } catch (LinkageError e) {
        logger.error("LinkageError ({})", e.getMessage());
        e.printStackTrace();
        throw new ApplicationException(e);
      }
    }

    return annotatedClasses;
  }
  
  /**
   * @return True if the given MetadataReader shows 
   * that the class is annotated by <code>javax.persistence.Enity</code>
   */
  private boolean isEntityClass(MetadataReader metadataReader) {
    Set<String> annTypes = metadataReader.getAnnotationMetadata().getAnnotationTypes();
    if (CollectionUtils.isEmpty(annTypes)) {
      return false;
    }
    
    return annTypes.contains(Entity.class.getName());
  }
  
  /**
   * 
   * @return True if the given class name match the excluded class patterns. 
   */
  private boolean isExcludedClass(String className) {
    if (excludedClassesRegexPatterns == null) { // All class is included.
      return false;
    }

    PatternCompiler compiler = new Perl5Compiler();
    PatternMatcher matcher = new Perl5Matcher();
    try {
      for (String regex : excludedClassesRegexPatterns) { //Test each patterns.
        logger.debug("Pattern is: {}", regex);
        Pattern pattern = compiler.compile(regex);
        if (matcher.matches(className, pattern)) {
          logger.debug("class [{}], matches [{}], so it is excluded.", className, pattern
              .getPattern());
          return true;
        }
      }
    } catch (MalformedPatternException e) {
      logger.warn("Malformed pattern [{}]", e.getMessage());
    }

    return false;
  }

  /**
   * @param exculdePatterns the exculdePatterns to set
   */
  public void setExcludedClassesRegexPatterns(String[] excludedClassesRegexPatterns) {
    this.excludedClassesRegexPatterns = excludedClassesRegexPatterns;
  }
}

在Spring的配置文件中这样写:
<bean id="sessionFactory" class="com.systop.common.core.dao.hibernate.AnnotationSessionFactoryBeanEx">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClassesLocations">
            <list>
                <value>classpath*:com/systop/**/model/*.class</value>
            </list>
        </property>
        <!--用正则表达式匹配不被scan的类-->
        <property name="excludedClassesRegexPatterns">
            <list>
                <value><![CDATA[^[\w\.]+Test[\w]+$]]></value>
            </list>
        </property>
</bean>

好了,一劳永逸!
哦,对了,提醒一下,上述代码使用了Spring2.5中的一些API,另外还有apache oro的正则表达式API。
分享到:
评论
1 楼 cats_tiger 2008-06-02  
多数时候,Domain类会在项目开始阶段得到确定,此时,annotatedClasses属性也就确定了,如果项目需求比较固定,那么上述改进没有什么明显的优势,但是,下列情况下就不同了。
1.如果项目需要重构。
2.如果需求模糊或者只确定了一部分需求,项目需要经常的添加一些Domain
3.如果公司有一个可复用模块库,里面包含权限、工作流等通用模块,这个复用库以jar包的形式提供给各个项目使用,spring的配置文件也在jar中。

相关推荐

    Spring+SpringMVC+JPA+Hibernate搭建

    10. 实现业务接口以及在applicationContext.xml中配置相应的bean,以让Spring容器管理这些业务对象。 11. 为项目添加JUnit测试支持,通过编写测试类和测试方法来验证业务逻辑的正确性。 12. 将SpringMVC整合到已经...

    配置hibernate数据源

    - 映射文件或注解(Annotated Classes):指定与数据库表对应的实体类。 4. 创建实体类。这些实体类将代表数据库中的表。可以通过注解或者XML映射文件来指定类与数据库表的映射关系。 5. 编写操作数据库的代码。...

    人脸数据库 Annotated Database

    这个特定的"Annotated Database"包含了240幅图像,每幅图像都经过了专业的标注,这意味着图像上的关键特征如眼睛、鼻子、嘴巴等都有精确的位置标记,这极大地促进了算法的训练和性能评估。 在人脸识别领域,数据库...

    eclipse 配置 hibernate tools 反向生成 pojo类 注解

    3. 在“Mapping Strategy”部分,选择“Annotated Java Classes”,这将生成带有注解的POJO类。 4. “Generation Options”中,你可以决定是否生成equals()、hashCode()和toString()方法,以及其他自定义选项。 5. ...

    Learning Spring Application Development

    Following this, you will explore how to implement the request handling layer using Spring annotated controllers. Other highlights include learning how to build the Java DAO implementation layer by ...

    spring-0.9-annotate:Spring0.9版本原始资料阅读-spring源码阅读

    源码中可以看到Spring如何封装数据库连接和事务管理,提供了一种声明式的方式,让开发者无需直接处理低级别的数据库操作。 在系统开源的标签下,Spring 0.9的源码阅读也为我们展示了开源软件的设计和开发流程。开源...

    IMM Annotated Database 人脸数据库

    IMM Annotated Database是一个专为人脸识别研究而设计的数据库,包含240幅精心标注的人脸图像。这个数据库在人脸识别领域具有重要的价值,因为它提供了一组标准化、有标记的图像,可供研究人员进行算法开发、测试和...

    Manning.Spring.in.Action.4th.Edition.2014.11.epub

    11.1. Integrating Hibernate with Spring 11.1.1. Declaring a Hibernate session factory 11.1.2. Building Spring-free Hibernate 11.2. Spring and the Java Persistence API 11.2.1. Configuring an entity ...

    the.annotated.turing

    《The Annotated Turing》是由Charles Petzold撰写的一本经典计算机科学著作,它深入解析了艾伦·图灵在1936年提出的图灵机模型,并以此为基础探讨了计算理论的基础。这本书对于理解计算机科学的基本原理至关重要,...

    The Annotated C++ Reference Manual

    隐式调度是指由μC++内核自动管理的任务调度,适用于那些对响应时间和确定性有较高要求的场景。 ##### 2.9.2 外部调度 外部调度允许开发者直接控制任务的执行时机,通常用于需要更高层次控制的应用场景。 #### ...

    The Annotated C++ Reference Manual part3

    The Annotated C++ Reference Manual 一共四个压缩包

    使用Hibernate逆向生成实体类的方法(注解和hbm.xml映射文件)

    ### 使用Hibernate逆向生成实体类的方法 在Java开发领域中,Hibernate作为一种流行的ORM(对象关系映射)框架,被广泛应用于将对象模型映射到基于SQL的关系型数据库上。通过Hibernate,开发者能够更加高效地处理...

    redis-3.0-annotated-unstable.zip

    redis-3.0-annotated-unstable.zipredis-3.0-annotated-unstable.zipredis-3.0-annotated-unstable.zipredis-3.0-annotated-unstable.zip

    spring2.5 jar

    5. **更多数据访问支持**:Spring 2.5增强了对JDBC、Hibernate、JPA等持久化技术的支持,提供了更简便的数据访问抽象,如JdbcTemplate和HibernateTemplate。 6. **国际化(Internationalization,i18n)**:Spring ...

    Thinking in Java 4th Edition Annotated Solutions Guide

    根据提供的文件信息,以下是对文件《Thinking in Java 4th Edition Annotated Solutions Guide》中所包含知识点的详细解释: 首先,文件标题《Thinking in Java 4th Edition Annotated Solutions Guide》指出了这是...

    The Annotated C++ Reference Manual.part2

    The Annotated C++ Reference Manual.part2

    The Common Language Infrastructure Annotated Standard

    The Common Language Infrastructure Annotated Standard

    The Annotated C++ Reference Manual(ARM)-Ch09

    本节将基于给定的文件信息——标题、描述、标签以及部分内容来深入探讨与第九章“ARM Classes”相关的知识点。 ### 一、ARM及其意义 《The Annotated C++ Reference Manual》这本书由Bjarne Stroustrup撰写,旨在...

Global site tag (gtag.js) - Google Analytics