[weld] GenericDao,Spring(2.5) VS Weld
wuhaixing
2010-04-17
对于还不知道什么是GenericDao的同学,推荐阅读
http://community.jboss.org/wiki/GenericDataAccessObjects 在开始weld文档中关于weld的部分之前,希望有个例子能给大家看,所以花了些时间研究,也在seamframework论坛请教了些问题,得到了他们热心的帮助。感兴趣的可以到 http://www.seamframework.org/Community/GenericDAO看看。 由于我对spring和weld都不是非常熟悉,所以实现方式可能不是非常恰当,欢迎讨论。 |
|
wuhaixing
2010-04-17
spring+hibernat的代码构成
FinderDispatcherGenericDaoImpl,这是最关键的核心类,其中有interceptor的实现和绑定: public class FinderDispatcherGenericDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements FactoryBean, Serializable { private static final long serialVersionUID = -3752572093862325307L; private Object servicesImpl; private Class<T> entityClass; private Class<?> daoInterface; private UsernameResolver usernameResolver; public Object getObject() throws Exception { ProxyFactory result = new ProxyFactory(); GenericDao<T, PK> genericDao = createGenericHibernateDao(); result.setTarget(genericDao); result.setInterfaces(new Class[]{daoInterface}); result.addAdvice(createGenericDaoInterceptor()); return result.getProxy(); } protected GenericDao<T, PK> createGenericHibernateDao() { GenericHibernateDaoImpl<T, PK> genericDao = new GenericHibernateDaoImpl<T, PK>(entityClass); genericDao.setSessionFactory(getSessionFactory()); genericDao.setHibernateTemplate(getHibernateTemplate()); genericDao.setUsernameResolver(usernameResolver); return genericDao; } private MethodInterceptor createGenericDaoInterceptor() { return new MethodInterceptor() { public Object invoke(MethodInvocation invocation) throws Throwable { /* * If the session will be opened at this place, the same method * closes the session and transaction */ boolean isSessionAvailable = isSessionAvailable(); if (!isSessionAvailable) { openSession(); } Object result = evaluateMethodInvocation(invocation); if (!isSessionAvailable) { closeSession(); } return result; } private Object evaluateMethodInvocation(MethodInvocation invocation) throws Throwable { Object result = null; Method method = invocation.getMethod(); if (method.isAnnotationPresent(Query.class)) { result = executeQuery(invocation); } else if (method.isAnnotationPresent(BulkUpdate.class)) { executeBulkUpdate(invocation); } else { result = delegateToServiceMethod(invocation); } return result; } private Object delegateToServiceMethod(MethodInvocation invocation) throws Throwable { Method serviceMethod = FinderDispatcherGenericDaoImpl.this.servicesImpl != null ? FinderDispatcherGenericDaoImpl.this.servicesImpl.getClass().getMethod(invocation.getMethod().getName(), invocation.getMethod().getParameterTypes()) : null; if (serviceMethod != null) { return serviceMethod.invoke(FinderDispatcherGenericDaoImpl.this.servicesImpl, invocation.getArguments()); } else { // should be only save, update, delete from the generic // dao return invocation.proceed(); } } private void executeBulkUpdate(MethodInvocation invocation) { openTransaction(); Method method = invocation.getMethod(); BulkUpdate bulkUpdate = method.getAnnotation(BulkUpdate.class); FinderExecutor target = (FinderExecutor) invocation.getThis(); target.executeUpdate(bulkUpdate.value(), invocation.getArguments()); } private boolean isSessionAvailable() { 。。。。 } private void openTransaction() { 。。。。 } private Object executeQuery(MethodInvocation invocation) { Method method = invocation.getMethod(); Query query = method.getAnnotation(Query.class); FinderExecutor target = (FinderExecutor) invocation.getThis(); if (query.limitClause()) { Object orginal[] = invocation.getArguments(); int len = orginal.length - 2; Object copy[] = new Object[len]; for (int i = 0; i < len; i++) { copy[i] = orginal[i]; } return target.executeFinder(query.value(), copy, method, (Integer) orginal[len], (Integer) orginal[len + 1]); } else { return target.executeFinder(query.value(), invocation.getArguments(), method, null, null); } } private void closeSession() { 。。。。。。 } private void commitTransaction(SessionHolder sessionHolder) { 。。。。。。。 } private void openSession() { 。。。。。 } }; } @SuppressWarnings(value = "unchecked") public Class getObjectType() { return daoInterface; } public boolean isSingleton() { return true; } public Object getServicesImpl() { return servicesImpl; } public void setServicesImpl(Object servicesImpl) { this.servicesImpl = servicesImpl; } public Class<T> getEntityClass() { return entityClass; } @Required public void setEntityClass(Class<T> entityClass) { this.entityClass = entityClass; } public Class<?> getDaoInterface() { return daoInterface; } @Required public void setDaoInterface(Class<?> daoInterface) { this.daoInterface = daoInterface; } @Required public void setUsernameResolver(UsernameResolver usernameResolver) { this.usernameResolver = usernameResolver; } } 相关的beans配置如下: <bean id="baseGenericDao" class="org.devproof.portal.core.module.common.dao.FinderDispatcherGenericDaoImpl" parent="hibernateDaoSupport" abstract="true"> <property name="usernameResolver" ref="usernameResolver"/ </bean> |
|
wuhaixing
2010-04-17
对应的weld实现分成了几个部分:
首先是interceptor: @InterceptorBinding @Retention(RUNTIME) @Target({METHOD, TYPE}) public @interface Dao { } @Interceptor @Dao public class DaoInterceptor { @PersistenceContext EntityManager em; private @Inject Logger logger; @AroundInvoke public Object createDao(InvocationContext ctx) throws Exception { Class<?> returnType = ctx.getMethod().getReturnType(); logger.info("create dao {}",returnType.getName()); if (!returnType.isInterface()) { throw new UnsupportedOperationException("Only results of methods " + "which produce implementations of an interface can be replaced!"); } Object result = ctx.proceed(); result = Proxy.newProxyInstance( returnType.getClassLoader(), new Class[] { returnType }, new DaoInvocationHandler(new GenericDaoImpl(em,returnType))); return result; } } public class DaoInvocationHandler implements InvocationHandler { private final Object delegate; public DaoInvocationHandler(Object delegate) { this.delegate = delegate; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { QuerySpecifiction querySpecification = getQueryAnnotation(method); if(querySpecification != null) { if (querySpecification.limitClause()) { int len = args.length - 2; Object copy[] = new Object[len]; for (int i = 0; i < len; i++) { copy[i] = args[i]; } return ((GenericDao)delegate).executeFinder(querySpecification.value(), copy, method, (Integer) args[len], (Integer) args[len + 1]); } else { return ((GenericDao)delegate).executeFinder(querySpecification.value(), args, method, null, null); } } return method.invoke(delegate, args); } private QuerySpecifiction getQueryAnnotation(Method m) { for (Annotation a : m.getAnnotations()) { if (a instanceof QuerySpecifiction) { return (QuerySpecifiction) a; } } for (Annotation a : m.getDeclaringClass().getAnnotations()) { if (a instanceof QuerySpecifiction) { return (QuerySpecifiction) a; } } return null; } } |
|
wuhaixing
2010-04-17
至于Dao的定义及调用,差别不多,spring中是:
public interface WidgetDao extends GenericDao<Widget,Long>{ @QuerySpecifiction("select w from Widget w order by w.name") public List<Widget> getWidgets(); } 加上xml配置: <bean id="widgetDao" parent="baseGenericDao"> <property name="daoInterface" value="WidgetDao"/> <property name="entityClass" value="WidgetEntity"/></bean> 调用为对Dao的get和set方法。 |
|
wuhaixing
2010-04-17
weld中interface一样
由一个produces方法加上interceptor来创建Dao: @Produces @Dao public WidgetDao getWidgetDao() { return null; } 调用为注入的field,不需要get及set方法: @Inject WidgetDao widgetDao |
|
wuhaixing
2010-04-17
至于负责执行具体任务的DaoImpl,几乎是完全一致的。只是interceptor的实现及绑定方式,相比较而言weld更清晰。
|
|
lonvea
2010-04-17
小兄弟,大哥给你秀一下我的weld实现。。
1.BaseDAO:所有DAO依赖注入的修饰类型 @Target( { TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented @Qualifier public @interface BaseDAO { } 2.ibatis中sqlmap修饰 @Retention(RetentionPolicy.RUNTIME) @Target({FIELD,METHOD}) @Qualifier public @interface SqlMap { } 3. sqlmap生产方法(依赖注出) public class SqlMapClientFactory { private static SqlMapClient sqlMapClient; ......... @Produces @SqlMap public static SqlMapClient getInstance(){ return sqlMapClient; } } 4.UserDAO:用户信息操作类 @BaseDAO public class UserDAOImpl implements UserDAO { @Inject @SqlMap private SqlMapClient sqlMapClient; @Override public void insert(UserDO userDO) throws DAOException { try { sqlMapClient.insert("UserDAO.insert", userDO); } catch (Exception e) { throw new DAOException(e); } } .... } 超级简单。。。 不过本人最近对JSF和JPA有强烈抵触情绪。NND,JSF感觉有点补靠谱了。改成velocity+servlet自己封装View层。 由于JPA无法对sql进行动态支持,分表操作等,改成ibatis。。 |
|
wuhaixing
2010-04-17
呵呵,简单直观的方式,但代码应该还是会多一些。另外没看懂你的Dao实现中insert参数的作用。
至于抵触情绪,大可不必,他们能发展到现在的样子,还是有可取之处的。 ibatis有他的优势,毕竟他是瞄着orm的缺点做的。 |
|
rrsy23
2010-04-19
还是做成NO DAO吧
直接一个service里面提供持久化服务就OK |
|
wuhaixing
2010-04-19
rrsy23 写道 还是做成NO DAO吧
直接一个service里面提供持久化服务就OK 其实这个实现并不是严格意义上的DAO,只是为了简化无处不在的@PersistenceContext 和 createQuery。从理论上来说,用接口声明query语句是有问题的,但这种方式的确会减少你敲键盘的次数。 |