使用AOP实现类型安全的泛型DAO
来源:百度文库 编辑:神马文学网 时间:2024/03/28 19:17:15
由于要求在项目中使用泛型的DAO,所以上网Google了一下,找到了IBM的一篇文章。文章讲得不错,但是有些地方不清楚,如果完全按照那篇文章可能还会遇到一些困难。所以写了这篇文章,解释如何在项目中加入泛型的DAO实现。
首先是总的类关系的UML图:
然后是在配置文件中的关系图:
其中,IStaffDao是我们自己定义的接口,这个接口类似:
public interface IStaffDAO extends GenericDao < Staff, Integer >{
public List listAll();
public Staff getByLogonAndId(String logon, Integer id);
// more
}
GenericDao 是泛型的 Dao 接口:
/** */ /**
* 2006-11-22
* 范型DAO接口
* @author Zou Ang
* Contact Zou Ang
*/
public interface GenericDao < T, PK extends Serializable > {
/** */ /**
* 保存一个对象到数据库
* @param newInstance 需要保存的对象
* @return
*/
PK create(T newInstance);
/** */ /**
* 从数据库读取一个对象
* @param id 主键
* @return
*/
T read(PK id);
/** */ /**
* 更新一个对象
* @param transientObject 被更新的对象
*/
void update(T transientObject);
/** */ /**
* 删除一个对象
* @param transientObject 被删除的对象
*/
void delete(T transientObject);
}
GenericDaoHibernateImpl 是 GenericDao 接口的泛型实现 :
/** */ /**
* 2006-11-22
* 范型DAO实现
* @author Zou Ang
* Contact Zou Ang
*/
public class GenericDaoHibernateImpl < T,PK extends Serializable >
extends HibernateDaoSupport
implements GenericDao < T, PK > ,FinderExecutor{
private Class < T > type;
private FinderNamingStrategy namingStrategy = new SimpleFinderNamingStrategy(); // Default. Can override in config
private FinderArgumentTypeFactory argumentTypeFactory = new SimpleFinderArgumentTypeFactory(); // Default. Can override in config
public GenericDaoHibernateImpl(Class < T > type){
this .type = type;
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#create(java.lang.Object)
*/
public PK create(T newInstance) {
return (PK)getHibernateTemplate().save(newInstance);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#delete(java.lang.Object)
*/
public void delete(T transientObject) {
getHibernateTemplate().delete(transientObject);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#read(java.io.Serializable)
*/
public T read(PK id) {
return (T)getHibernateTemplate().get(type, id);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#update(java.lang.Object)
*/
public void update(T transientObject) {
getHibernateTemplate().update(transientObject);
}
public List < T > executeFinder(Method method, final Object[] queryArgs)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (List < T > ) namedQuery.list();
}
public Iterator < T > iterateFinder(Method method, final Object[] queryArgs)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (Iterator < T > ) namedQuery.iterate();
}
private Query prepareQuery(Method method, Object[] queryArgs)
{
final String queryName = getNamingStrategy().queryNameFromMethod(type, method);
final Query namedQuery = getSession().getNamedQuery(queryName);
String[] namedParameters = namedQuery.getNamedParameters();
if (namedParameters.length == 0 )
{
setPositionalParams(queryArgs, namedQuery);
} else {
setNamedParams(namedParameters, queryArgs, namedQuery);
}
return namedQuery;
}
private void setPositionalParams(Object[] queryArgs, Query namedQuery)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
{
namedQuery.setParameter(i, arg, argType);
}
else
{
namedQuery.setParameter(i, arg);
}
}
}
}
private void setNamedParams(String[] namedParameters, Object[] queryArgs, Query namedQuery)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
{
namedQuery.setParameter(namedParameters[i], arg, argType);
}
else
{
if (arg instanceof Collection) {
namedQuery.setParameterList(namedParameters[i], (Collection) arg);
}
else
{
namedQuery.setParameter(namedParameters[i], arg);
}
}
}
}
}
public FinderNamingStrategy getNamingStrategy()
{
return namingStrategy;
}
public void setNamingStrategy(FinderNamingStrategy namingStrategy)
{
this .namingStrategy = namingStrategy;
}
public FinderArgumentTypeFactory getArgumentTypeFactory()
{
return argumentTypeFactory;
}
public void setArgumentTypeFactory(FinderArgumentTypeFactory argumentTypeFactory)
{
this .argumentTypeFactory = argumentTypeFactory;
}
}
FinderNamingStrategy 是查找方法的命名规范:
public interface FinderNamingStrategy
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod);
}
目前有两个命名查找策略,使用的是
Simple 的,也就是直接是 < 类型名 >.< 方法名 > 的形式。
public class SimpleFinderNamingStrategy implements FinderNamingStrategy
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod)
{
return findTargetType.getSimpleName() + " . " + finderMethod.getName();
}
}
FinderArgumentTypeFactory 目前还没有什么作用,主要是返回自定义的 Hibernate 类型:
public class SimpleFinderArgumentTypeFactory implements FinderArgumentTypeFactory
{
public Type getArgumentType(Object arg)
{
// if(arg instanceof Enum)
// {
// return getEnumType(arg.getClass());
// }
// else
// {
return null ;
// }
}
// private Type getEnumType(Class extends Object> argClass)
// {
// Properties p = new Properties();
// p.setProperty("enumClassName", argClass.getName());
// Type enumType = TypeFactory.heuristicType("org.hibernate.demo.EnumUserType", p);
// return enumType;
// }
}
FinderIntroductionAdvisor 和 FinderIntroductionInterceptor:
public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor
{
public FinderIntroductionAdvisor()
{
super ( new FinderIntroductionInterceptor());
}
}
public class FinderIntroductionInterceptor implements IntroductionInterceptor
{
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
FinderExecutor executor = (FinderExecutor) methodInvocation.getThis();
String methodName = methodInvocation.getMethod().getName();
if (methodName.startsWith( " get " ) || methodName.startsWith( " list " ))
{
Object[] arguments = methodInvocation.getArguments();
return executor.executeFinder(methodInvocation.getMethod(), arguments);
}
else if (methodName.startsWith( " iterate " ))
{
Object[] arguments = methodInvocation.getArguments();
return executor.iterateFinder(methodInvocation.getMethod(), arguments);
}
// else if(methodName.startsWith("scroll"))
// {
// Object[] arguments = methodInvocation.getArguments();
// return executor.scrollFinder(methodInvocation.getMethod(), arguments);
// }
else
{
return methodInvocation.proceed();
}
}
public boolean implementsInterface(Class intf)
{
return intf.isInterface() && FinderExecutor. class .isAssignableFrom(intf);
}
}
然后就到了配置文件了:
< bean id ="abstractDaoTarget"
class ="com.gdnfha.atcs.common.service.dao.hibernate.GenericDaoHibernateImpl"
abstract ="true" >
< property name ="sessionFactory" >
< ref local ="sessionFactory" />
property >
< property name ="namingStrategy" >
< ref bean ="simpleFinderNamingStratrgy" />
property >
bean >
< bean id ="abstractDao"
class ="org.springframework.aop.framework.ProxyFactoryBean"
abstract ="true" >
< property name ="interceptorNames" >
< list >
< value > finderIntroductionAdvisor value >
list >
property >
bean >
< bean id ="finderIntroductionAdvisor"
class ="com.gdnfha.atcs.common.service.dao.finder.FinderIntroductionAdvisor" />
< bean id ="namingStrategy"
class ="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" >
< property name ="staticField" >
< value > org.hibernate.cfg.ImprovedNamingStrategy.INSTANCE value >
property >
bean >
< bean id ="extendedFinderNamingStrategy"
class ="com.gdnfha.atcs.common.service.dao.finder.impl.ExtendedFinderNamingStrategy" />
< bean id ="simpleFinderNamingStratrgy" class ="com.gdnfha.atcs.common.service.dao.finder.impl.SimpleFinderNamingStrategy" />
< bean id ="staffDao" parent ="abstractDao" >
< property name ="proxyInterfaces" >
< value > com.gdnfha.atcs.maintain.service.dao.IStaffDAO value >
property >
< property name ="target" >
< bean parent ="abstractDaoTarget" >
< constructor-arg >
< value > com.gdnfha.atcs.common.pojo.Staff value >
constructor-arg >
bean >
property >
bean >
还要在Staff.hbm.xml中配置:
< query name ="Staff.getByLogonAndId" >
query >
这里要特别注意 这个要写在 的外面,否则会提示Mapping Exception:No Named Query
好了,大公告成了!现在可以跟以前一样使用
appContext.getBean("staffDao"); 这样进行测试了
staffDao.read(new Integer(1));
staffDao.getByLogonAndId("abc",new Integer(2));
首先是总的类关系的UML图:
然后是在配置文件中的关系图:
其中,IStaffDao是我们自己定义的接口,这个接口类似:
public interface IStaffDAO extends GenericDao < Staff, Integer >{
public List listAll();
public Staff getByLogonAndId(String logon, Integer id);
// more
}
GenericDao
/** */ /**
* 2006-11-22
* 范型DAO接口
* @author Zou Ang
* Contact Zou Ang
*/
public interface GenericDao < T, PK extends Serializable > {
/** */ /**
* 保存一个对象到数据库
* @param newInstance 需要保存的对象
* @return
*/
PK create(T newInstance);
/** */ /**
* 从数据库读取一个对象
* @param id 主键
* @return
*/
T read(PK id);
/** */ /**
* 更新一个对象
* @param transientObject 被更新的对象
*/
void update(T transientObject);
/** */ /**
* 删除一个对象
* @param transientObject 被删除的对象
*/
void delete(T transientObject);
}
GenericDaoHibernateImpl 是 GenericDao 接口的泛型实现 :
/** */ /**
* 2006-11-22
* 范型DAO实现
* @author Zou Ang
* Contact Zou Ang
*/
public class GenericDaoHibernateImpl < T,PK extends Serializable >
extends HibernateDaoSupport
implements GenericDao < T, PK > ,FinderExecutor{
private Class < T > type;
private FinderNamingStrategy namingStrategy = new SimpleFinderNamingStrategy(); // Default. Can override in config
private FinderArgumentTypeFactory argumentTypeFactory = new SimpleFinderArgumentTypeFactory(); // Default. Can override in config
public GenericDaoHibernateImpl(Class < T > type){
this .type = type;
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#create(java.lang.Object)
*/
public PK create(T newInstance) {
return (PK)getHibernateTemplate().save(newInstance);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#delete(java.lang.Object)
*/
public void delete(T transientObject) {
getHibernateTemplate().delete(transientObject);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#read(java.io.Serializable)
*/
public T read(PK id) {
return (T)getHibernateTemplate().get(type, id);
}
/**/ /* (non-Javadoc)
* @see com.gdnfha.atcs.common.service.dao.GenericDao#update(java.lang.Object)
*/
public void update(T transientObject) {
getHibernateTemplate().update(transientObject);
}
public List < T > executeFinder(Method method, final Object[] queryArgs)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (List < T > ) namedQuery.list();
}
public Iterator < T > iterateFinder(Method method, final Object[] queryArgs)
{
final Query namedQuery = prepareQuery(method, queryArgs);
return (Iterator < T > ) namedQuery.iterate();
}
private Query prepareQuery(Method method, Object[] queryArgs)
{
final String queryName = getNamingStrategy().queryNameFromMethod(type, method);
final Query namedQuery = getSession().getNamedQuery(queryName);
String[] namedParameters = namedQuery.getNamedParameters();
if (namedParameters.length == 0 )
{
setPositionalParams(queryArgs, namedQuery);
} else {
setNamedParams(namedParameters, queryArgs, namedQuery);
}
return namedQuery;
}
private void setPositionalParams(Object[] queryArgs, Query namedQuery)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
{
namedQuery.setParameter(i, arg, argType);
}
else
{
namedQuery.setParameter(i, arg);
}
}
}
}
private void setNamedParams(String[] namedParameters, Object[] queryArgs, Query namedQuery)
{
// Set parameter. Use custom Hibernate Type if necessary
if (queryArgs != null )
{
for ( int i = 0 ; i < queryArgs.length; i ++ )
{
Object arg = queryArgs[i];
Type argType = getArgumentTypeFactory().getArgumentType(arg);
if (argType != null )
{
namedQuery.setParameter(namedParameters[i], arg, argType);
}
else
{
if (arg instanceof Collection) {
namedQuery.setParameterList(namedParameters[i], (Collection) arg);
}
else
{
namedQuery.setParameter(namedParameters[i], arg);
}
}
}
}
}
public FinderNamingStrategy getNamingStrategy()
{
return namingStrategy;
}
public void setNamingStrategy(FinderNamingStrategy namingStrategy)
{
this .namingStrategy = namingStrategy;
}
public FinderArgumentTypeFactory getArgumentTypeFactory()
{
return argumentTypeFactory;
}
public void setArgumentTypeFactory(FinderArgumentTypeFactory argumentTypeFactory)
{
this .argumentTypeFactory = argumentTypeFactory;
}
}
FinderNamingStrategy 是查找方法的命名规范:
public interface FinderNamingStrategy
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod);
}
目前有两个命名查找策略,使用的是
Simple 的,也就是直接是 < 类型名 >.< 方法名 > 的形式。
public class SimpleFinderNamingStrategy implements FinderNamingStrategy
{
public String queryNameFromMethod(Class findTargetType, Method finderMethod)
{
return findTargetType.getSimpleName() + " . " + finderMethod.getName();
}
}
FinderArgumentTypeFactory 目前还没有什么作用,主要是返回自定义的 Hibernate 类型:
public class SimpleFinderArgumentTypeFactory implements FinderArgumentTypeFactory
{
public Type getArgumentType(Object arg)
{
// if(arg instanceof Enum)
// {
// return getEnumType(arg.getClass());
// }
// else
// {
return null ;
// }
}
// private Type getEnumType(Class extends Object> argClass)
// {
// Properties p = new Properties();
// p.setProperty("enumClassName", argClass.getName());
// Type enumType = TypeFactory.heuristicType("org.hibernate.demo.EnumUserType", p);
// return enumType;
// }
}
FinderIntroductionAdvisor 和 FinderIntroductionInterceptor:
public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor
{
public FinderIntroductionAdvisor()
{
super ( new FinderIntroductionInterceptor());
}
}
public class FinderIntroductionInterceptor implements IntroductionInterceptor
{
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
FinderExecutor executor = (FinderExecutor) methodInvocation.getThis();
String methodName = methodInvocation.getMethod().getName();
if (methodName.startsWith( " get " ) || methodName.startsWith( " list " ))
{
Object[] arguments = methodInvocation.getArguments();
return executor.executeFinder(methodInvocation.getMethod(), arguments);
}
else if (methodName.startsWith( " iterate " ))
{
Object[] arguments = methodInvocation.getArguments();
return executor.iterateFinder(methodInvocation.getMethod(), arguments);
}
// else if(methodName.startsWith("scroll"))
// {
// Object[] arguments = methodInvocation.getArguments();
// return executor.scrollFinder(methodInvocation.getMethod(), arguments);
// }
else
{
return methodInvocation.proceed();
}
}
public boolean implementsInterface(Class intf)
{
return intf.isInterface() && FinderExecutor. class .isAssignableFrom(intf);
}
}
然后就到了配置文件了:
< bean id ="abstractDaoTarget"
class ="com.gdnfha.atcs.common.service.dao.hibernate.GenericDaoHibernateImpl"
abstract ="true" >
< property name ="sessionFactory" >
< ref local ="sessionFactory" />
property >
< property name ="namingStrategy" >
< ref bean ="simpleFinderNamingStratrgy" />
property >
bean >
< bean id ="abstractDao"
class ="org.springframework.aop.framework.ProxyFactoryBean"
abstract ="true" >
< property name ="interceptorNames" >
< list >
< value > finderIntroductionAdvisor value >
list >
property >
bean >
< bean id ="finderIntroductionAdvisor"
class ="com.gdnfha.atcs.common.service.dao.finder.FinderIntroductionAdvisor" />
< bean id ="namingStrategy"
class ="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" >
< property name ="staticField" >
< value > org.hibernate.cfg.ImprovedNamingStrategy.INSTANCE value >
property >
bean >
< bean id ="extendedFinderNamingStrategy"
class ="com.gdnfha.atcs.common.service.dao.finder.impl.ExtendedFinderNamingStrategy" />
< bean id ="simpleFinderNamingStratrgy" class ="com.gdnfha.atcs.common.service.dao.finder.impl.SimpleFinderNamingStrategy" />
< bean id ="staffDao" parent ="abstractDao" >
< property name ="proxyInterfaces" >
< value > com.gdnfha.atcs.maintain.service.dao.IStaffDAO value >
property >
< property name ="target" >
< bean parent ="abstractDaoTarget" >
< constructor-arg >
< value > com.gdnfha.atcs.common.pojo.Staff value >
constructor-arg >
bean >
property >
bean >
还要在Staff.hbm.xml中配置:
< query name ="Staff.getByLogonAndId" >
query >
这里要特别注意
好了,大公告成了!现在可以跟以前一样使用
appContext.getBean("staffDao"); 这样进行测试了
staffDao.read(new Integer(1));
staffDao.getByLogonAndId("abc",new Integer(2));
使用AOP实现类型安全的泛型DAO
使用AOP实现类型安全的泛型DAO - 东方未名 - BlogJava
使用 Hibernate 和 Spring AOP 构建泛型类型安全的 DAO - baggio785的专栏
使用 Hibernate 和 Spring AOP 构建泛型类型安全的 DAO
基于.Net的AOP实现技术
Aspectwerkz动态实现AOP
AspectJ如何实现AOP
恋风的Blog: AspectJ如何实现AOP
AOP@Work: 使用方面的下几个步骤
浅析Spring 2.X中AOP的使用
Spring2.X中AOP的使用 - 边城愚人 - BlogJava
Spring2.X中AOP的使用 - 边城愚人 - BlogJava
Spring 2.X 中AOP的使用浅析
如何使用 DAO 的 MS Excel 中创建 MS Access 数据库
SpringFramework中的AOP简单使用
Spring中的AOP简单使用
塑料杯的安全使用
塑料杯的安全使用
关联词使用的四种病句类型
使用手机的安全事项
系统“内存不足”的解决之dao
Spring2.X的 AOP支持
使用Go语言实现的代理服务器
十三香龙虾调料的类型及使用