`

扩展 AnnotationSessionFactoryBean 实现domain 对象自动加载

阅读更多
在hibernate和spring集成时,使用annotation方式来替代xml配置方式可以减少项目中配置文件的数量。使项目结构看起来更佳简洁、干净。为此,spring提供了AnnotationSessionFactoryBean 类。但是,在配置的时候,这个类不是很灵活,eg:

Java代码
   <bean id="sessionFactory" class="com.derbysoft.hibernate.core.LocaleAnnotationSessionFactoryBean">     
    <property name="dataSource" ref="dataSource"/>     
    <property name="hibernateProperties">     
        <props>     
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
            <prop key="hibernate.show_sql">true</prop>  
        </props>     
    </property>  
   <property name="annotatedClasses">     
        <list>     
            <value>com.example.domain.Role</value>     
            <value>com.example.domain.Permission</value>     
        </list>     
    </property>        
</bean> 

    <bean id="sessionFactory" class="com.derbysoft.hibernate.core.LocaleAnnotationSessionFactoryBean">  
    <property name="dataSource" ref="dataSource"/>  
    <property name="hibernateProperties">  
        <props>  
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>  
    </property>
   <property name="annotatedClasses">  
        <list>  
            <value>com.example.domain.Role</value>  
            <value>com.example.domain.Permission</value>  
        </list>  
    </property>     
</bean> 注意到这几行配置代码:

Java代码
<property name="annotatedClasses">     
     <list>     
         <value>com.example.domain.Role</value>     
         <value>com.example.domain.Permission</value>     
     </list>     
</property> 

   <property name="annotatedClasses">  
        <list>  
            <value>com.example.domain.Role</value>  
            <value>com.example.domain.Permission</value>  
        </list>  
   </property> 在你的项目中,你的所有持久化类都需要手动配置到annotatedClasses属性中,很不灵活。所以,为了能过达到更高的灵活性,我们需要自己去扩展AnnotationSessionFactoryBean sessionFacotory工厂类。spring team 也考虑到这一点,为我们提供了预留方法,方便我们实现客户化的功能,eg:

Java代码
/** 
* To be implemented by subclasses that want to to perform custom 
* post-processing of the AnnotationConfiguration object after this 
* FactoryBean performed its default initialization. 
* @param config the current AnnotationConfiguration object 
* @throws HibernateException in case of Hibernate initialization errors 
*/ 
protected void postProcessAnnotationConfiguration(AnnotationConfiguration config)  
        throws HibernateException {  


/**
* To be implemented by subclasses that want to to perform custom
* post-processing of the AnnotationConfiguration object after this
* FactoryBean performed its default initialization.
* @param config the current AnnotationConfiguration object
* @throws HibernateException in case of Hibernate initialization errors
*/
protected void postProcessAnnotationConfiguration(AnnotationConfiguration config)
throws HibernateException {
} 这个方法就是 AnnotationSessionFactoryBean 提供给我们让我们能够实现自己特定功能的方法。因此,我们可以创建一个子类,然后继承AnnotationSessionFactoryBean 实现此方法。

      附件中,是我的详细实代码,需要的可以进行下载。下面,我来详细分析一下我的实现思路,希望大家多多指教。

     大家都知道,在使用spring的时候,spring在加载bean的时候可以按这样一种路径方式来加载,eg:classpath*:com/derbysoft/**/*.class,spring就会加载com.derbysoft包下及其所有子包的class文件,这个叫ant-style模式。在使用struts的时候,我们用annotation注释action的时候。会在web.xml配置这样一段代码:

Java代码
<filter>  
    <filter-name>struts2</filter-name>  
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>  
    <init-param>  
        <param-name>actionPackages</param-name>  
        <param-value>com.derbysoft.drental.action</param-value>  
    </init-param>  
</filter> 

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
    <param-name>actionPackages</param-name>
    <param-value>com.derbysoft.drental.action</param-value>
  </init-param>
</filter> 会指定一个actionPackages属性,然后struts在初始化的时候会认为这个指定的包或子包下,所有的类为action类。(当然在搜索过程中,struts默认会进行过滤,你也可以自己实现过滤条件,eg:没被注解的类不进行加载)

       在我实现的代码中,我参照了这两种模式的实现,底层代码都是依赖spring和struts的核心代码的。

Java代码
/** 
* @see AnnotationSessionFactoryBean#postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration) 
*/ 
@Override 
protected void postProcessAnnotationConfiguration(AnnotationConfiguration config) throws HibernateException {  
    DomainClassLoader[] domainClassLoaders = DomainClassLoaderFactory.buildDomainClassLoader(annotatedClassesLocations);  
    for (DomainClassLoader domainClassLoader : domainClassLoaders) {  
        if (domainClassLoader == null) continue;  
        Set<Class<? extends Class>> annClasses = domainClassLoader.loadAnnotatedClasses();  
          
        for (Class annClass : annClasses) {  
            config.addAnnotatedClass(annClass);  
        }  
    }  


/**
* @see AnnotationSessionFactoryBean#postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration)
*/
@Override
protected void postProcessAnnotationConfiguration(AnnotationConfiguration config) throws HibernateException {
DomainClassLoader[] domainClassLoaders = DomainClassLoaderFactory.buildDomainClassLoader(annotatedClassesLocations);
for (DomainClassLoader domainClassLoader : domainClassLoaders) {
if (domainClassLoader == null) continue;
Set<Class<? extends Class>> annClasses = domainClassLoader.loadAnnotatedClasses();

for (Class annClass : annClasses) {
config.addAnnotatedClass(annClass);
}
}
} 这是整个类的核心代码,我们通过工厂模式来获得不同加载domain方式的实现(spring ant-sttyle模式和struts模式)



Java代码
/** 
* DomainClassLoader 
* @author leo 

*/ 
public static  abstract class DomainClassLoader {  
    protected String[] annotatedClassesLocations;  
      
    public DomainClassLoader(String[] annotatedClassesLocations) {  
        this.annotatedClassesLocations = annotatedClassesLocations;  
    }  
    /** 
     *  
     * @return set collection of of domain class that has annotation 
     */ 
    public abstract Set<Class<? extends Class>> loadAnnotatedClasses();   


/**
* DomainClassLoader
* @author leo
*
*/
public static  abstract class DomainClassLoader {
protected String[] annotatedClassesLocations;

public DomainClassLoader(String[] annotatedClassesLocations) {
this.annotatedClassesLocations = annotatedClassesLocations;
}
/**
*
* @return set collection of of domain class that has annotation
*/
public abstract Set<Class<? extends Class>> loadAnnotatedClasses();
} 这段代码是加载类的抽象,不同的实现都必须去继承它,eg:

Java代码
/** 
*  struts action pattern implements 
* @author leo 
* @see ResolverUtil 
*/ 
public static class PackageDomainClassLoaderProvider extends DomainClassLoader {  
    public PackageDomainClassLoaderProvider(String[] annotatedClassesLocations) {  
        super(annotatedClassesLocations);  
    }  
      
    @Override 
    public Set<Class<? extends Class>> loadAnnotatedClasses() {  
        ResolverUtil<Class> resolver = new ResolverUtil<Class>();  
        resolver.find(new ResolverUtil.AnnotatedWith(Entity.class), annotatedClassesLocations);  
        Set<Class<? extends Class>> actionClasses = resolver.getClasses();  
          
        return actionClasses;  
    }  


/**
*  struts action pattern implements
* @author leo
* @see ResolverUtil
*/
public static class PackageDomainClassLoaderProvider extends DomainClassLoader {
public PackageDomainClassLoaderProvider(String[] annotatedClassesLocations) {
super(annotatedClassesLocations);
}

@Override
public Set<Class<? extends Class>> loadAnnotatedClasses() {
        ResolverUtil<Class> resolver = new ResolverUtil<Class>();
        resolver.find(new ResolverUtil.AnnotatedWith(Entity.class), annotatedClassesLocations);
        Set<Class<? extends Class>> actionClasses = resolver.getClasses();
       
        return actionClasses;
}
}  这个就是struts 包模式的实现,主要的业务是通过ResolverUtil这个struts类来实现的。

  最后通过工厂方法返回一个DomainClassLoader 对象,eg:

Java代码
/** 
* DomainClassLoader Factory 
* @author leo 

*/ 
public static class DomainClassLoaderFactory {  
    /** 
     *  
     * @param includedClass 
     * @param excludedClass 
     * @return array of DomainClassLoader 
     */ 
    public static DomainClassLoader[] buildDomainClassLoader(String[] includedClasses) {  
        List<String> packages = new ArrayList<String>();  
        List<String> regexClasses = new ArrayList<String>();  
        DomainClassLoader[] domainClassLoaders = new DomainClassLoader[2];  
        for (String regexOrpackage : includedClasses) {  
            if (regexOrpackage.contains(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {  
                regexClasses.add(regexOrpackage);  
            } else {  
                packages.add(regexOrpackage);  
            }  
        }  
        if (packages.size() != 0) {  
            DomainClassLoader domainClassLoader = new PackageDomainClassLoaderProvider(packages.toArray(new String[packages.size()]));  
            domainClassLoaders[0] = domainClassLoader;  
        }  
        if (regexClasses.size() != 0) {  
            DomainClassLoader domainClassLoader = new RegexDomainClassLoaderProvider(regexClasses.toArray(new String[regexClasses.size()]));  
            domainClassLoaders[1] = domainClassLoader;    
        }  
        return domainClassLoaders;  
    }  


/**
* DomainClassLoader Factory
* @author leo
*
*/
public static class DomainClassLoaderFactory {
/**
*
* @param includedClass
* @param excludedClass
* @return array of DomainClassLoader
*/
public static DomainClassLoader[] buildDomainClassLoader(String[] includedClasses) {
List<String> packages = new ArrayList<String>();
List<String> regexClasses = new ArrayList<String>();
DomainClassLoader[] domainClassLoaders = new DomainClassLoader[2];
for (String regexOrpackage : includedClasses) {
if (regexOrpackage.contains(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
regexClasses.add(regexOrpackage);
} else {
packages.add(regexOrpackage);
}
}
if (packages.size() != 0) {
DomainClassLoader domainClassLoader = new PackageDomainClassLoaderProvider(packages.toArray(new String[packages.size()]));
domainClassLoaders[0] = domainClassLoader;
}
if (regexClasses.size() != 0) {
DomainClassLoader domainClassLoader = new RegexDomainClassLoaderProvider(regexClasses.toArray(new String[regexClasses.size()]));
domainClassLoaders[1] = domainClassLoader;
}
return domainClassLoaders;
}
} 最后,我配置的时候只需这样:

Java代码
<property name="annotatedClassesLocations">     
     <list>     
         <value>classpath*:com/example/**/domain/*.class</value>   
         <value>com.example.domain</value>     
     </list>     
</property>  

   <property name="annotatedClassesLocations">  
        <list>  
            <value>classpath*:com/example/**/domain/*.class</value>
            <value>com.example.domain</value>  
        </list>  
    </property>  spring在加载的时候,会去匹配类路径下com.example.xxx.domain.xxx.class 类和com.example.domain包及其子包下所有的类。至于具体的实现细节请下载附件

分享到:
评论
1 楼 capturefuture 2011-09-28  
AnnotationSessionFacotoryBean中有一个属性叫,annotatedPackages可以直接填包的名字啊,不用自己扩展吧

相关推荐

    让Hibernate同时支持xml和注解两种映射方式

    要让Hibernate同时支持XML和注解映射,我们可以创建一个新的配置类,该类扩展`AnnotationSessionFactoryBean`,并在需要时调用其父类`LocalSessionFactoryBean`的方法来处理XML映射。这样,我们就可以拥有一个单一的...

    JPA

    `mappedBy`属性用于指定反向映射的字段,`fetch`属性则用于指定加载策略,如`EAGER`立即加载或`LAZY`延迟加载。 - **多对多(Many-to-Many)**:这种关系涉及多个实体之间的关联。`@ManyToMany`注解用于映射这种...

    org.springframework.orm.hibernate3.LocalSessionFactoryBean

    2. **Hibernate**:一个开放源码的对象关系映射框架,允许开发者将Java对象映射到数据库表中。它简化了持久化层的开发工作,使开发者能够更专注于业务逻辑的编写。 3. **LocalSessionFactoryBean**:Spring框架中的...

    hibernate中的注释的几种配置方式

    例如,使用UUID作为主键时,可以通过`@GenericGenerator(name="system-uuid",strategy="uuid")`和`@GeneratedValue(generator="system-uuid")`组合来实现。 #### 2. Spring下的SessionFactory配置 - **...

    专题资料(2021-2022年)javaWEB模块物流项目二.doc

    通过使用Spring Data,开发者无需手动编写大量的DAO方法,只需定义好Repository接口,Spring Data就能自动生成对应的实现。 2. **数据库设计与管理**:项目使用了Oracle数据库,通过PowerDesigner工具进行数据库...

    spring2.5+hibernate3.2+struts2.0组合配置说明

    Hibernate 是一个开放源代码的对象关系映射(ORM)工具,它可以将 Java 类映射为数据库表,并自动将 Java 应用程序数据转换为 SQL 语句。Hibernate3.2 版本引入了许多新特性,如延迟加载、批处理等,以提高性能和...

    Hibernate 注解

    本文将深入探讨Hibernate注解的使用,包括SessionFactory的配置、POJO类的声明、主键的设定、普通字段的处理以及级联操作和一对一关联的实现。 首先,我们来看SessionFactory的配置。在传统的XML配置中,我们需要...

    SSH框架整合

    在业务层(Service)和数据访问层(DAO)中,使用@Autowired注解或XML配置文件来实现依赖注入,使得Spring管理的对象能够自动获取所需的SessionFactory或HibernateTemplate实例。 ### 7. 测试与运行 完成以上配置后...

    Struts2+Hibernate+Spring项目小结――Hibernate部分

    通过这种方式,开发人员可以在不编写XML映射文件的情况下,利用Java注解实现对象和数据库之间的映射,简化了开发过程,提高了开发效率。 在实际项目中,还需要注意其他配置,比如事务管理、异常处理等。Spring提供...

    ssh,ssh,ssh

    Hibernate是Java环境下的一款开源的对象关系映射(ORM)框架,可以有效地将Java对象映射到数据库表中,从而简化了数据持久化操作。 ### Spring与Struts的集成 在给定的内容中提到了Spring与Struts的集成方式,具体...

    中文分词检索IKAnalyzer3.2.3Stable+hibernate-search3.4.0.Final

    - **扩展词典**:`&lt;entry key="ext_dict"&gt;/dic/extendWord.dic&lt;/entry&gt;`指定了自定义扩展词典的路径。 - **停用词典**:`&lt;entry key="ext_stopwords"&gt;/dic/stopWords.dic&lt;/entry&gt;`指定了停用词的路径。 3. **...

    struts2+hibernate+spring

    - **ContextLoaderListener**:这是Spring框架中的一个监听器,用于在启动时加载Spring的配置文件。具体配置如下: ```xml &lt;param-name&gt;contextConfigLocation &lt;param-value&gt;classpath*:spring/*.xml ...

    spring配置文件

    自Spring 2.5.6版本开始,`AnnotationSessionFactoryBean`增加了`setPackagesToScan`方法,这是一个重要的改进。此方法允许我们在配置文件中直接指定需要扫描的实体类包名,从而自动发现并注册实体类,无需手动配置...

    项目框架SSH2技术说明文档

    《SSH2框架零配置技术详解》 SSH2框架,由Struts2、Spring和Hibernate2组成,是Java Web开发中...在实际项目中,结合Spring的自动扫描和依赖注入功能,可以进一步实现更全面的零配置,实现更加灵活和高效的开发模式。

    SSH框架的优化

    Spring框架的自动装配特性可以减少XML配置,通过`autowire`属性实现。`byName`根据bean名称匹配,`byType`根据bean类型匹配。可以在`beans`节点中设置全局自动装配,但需要注意,过度依赖自动装配可能导致组件间...

    SSH项目搭建步骤

    - 可以选择将 Hibernate 和 Spring 的配置合并,通过 Spring 的 `LocalSessionFactoryBean` 或 `AnnotationSessionFactoryBean` 来管理 Hibernate 的 SessionFactory。 6. **配置启动环境** - 配置 `web.xml`,...

    Spring集成Struts、Hibernate.pdf

    &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt; &lt;value&gt;com.example.entity.Book&lt;/value&gt; &lt;prop key="hibernate.dialect"&gt;org....

Global site tag (gtag.js) - Google Analytics