两个蝴蝶飞 2009-05-28
论坛中关联的地址:
http://www.iteye.com/topic/397854
直接上代码比较能说明问题。
首先是一个工具类SpringContextTool.java,getIdValue方法原本其他工具类中的方法,挪过来放在一起说方便。虽然是JDK1.5的编程风格,但是主要技巧同样适用于JDK1.4。
public class SpringContextTool implements ApplicationContextAware { /**Spring应用上下文环境*/ private static ApplicationContext applicationContext; /**实现ApplicationContextAware接口的回调方法,设置上下文环境 * @param applicationContext */ public void setApplicationContext(ApplicationContext applicationContext) { SpringContextTool.applicationContext = applicationContext; } public static SessionFactory getSessionFactory() { Assert.notNull(applicationContext, "applicationContext is null,请确保spring容器正常启动"); return (SessionFactory) applicationContext.getBean("sessionFactory"); } public static ClassMetadata getClassMetadata(Class<?> cls) { return getSessionFactory().getClassMetadata(cls); } /**得到一个model的id的值,可以直接获得id而不触发sql的产生,适合ManyToOne的场景 * @param model 有可能是CGLib增强之后的对象 * @return id */ public static String getIdValue(BaseModel model) { if (model instanceof HibernateProxy) { return (String) ((HibernateProxy) model).getHibernateLazyInitializer().getIdentifier(); } return (String) getClassMetadata(model.getClass()).getIdentifier(model, EntityMode.POJO); } }
1.这里的applicationContext属性是static的,觉得奇怪吧,没办法啊,为了追求getIdValue是static的,因为Model中或者是BaseModel中实现HashCode或者是equals最好是能调用static的方法,而不是有状态的。
2.getIdValue方法中,参数model可以是Object类型,其中实现方法可以看到,如果是代理对象HibernateProxy,可直接得到他的ID,如果是非代理对象,通过配置信息一样可以得到ID。传入参数可以改成Object类型,返回类型也可以根据需要修改成Object。
下面是我写的BaseModel中的应用(注意hashCode方法的实现,我这里规定ID是String类型的,其他类型的ID一样可以借鉴),仅供参考:
public abstract class BaseModel<E> implements Cloneable, Serializable { public int hashCode() { String idStr = SpringContextTool.getIdValue(this); return idStr == null ? super.hashCode() : idStr.hashCode(); } public boolean equals(Object other) { if (other == null) { return false; } if (other == this) { return true; } /*因为字节码增强的关系,getClass()不能用作判断的依据*/ if (getClass().getPackage() != other.getClass().getPackage()) { return false; } if (hashCode() == other.hashCode()) { return true; } return false; } /**日志对象*/ protected final Logger log = Logger.getLogger(getClass()); /**覆盖toString方法,ToStringStyle取值为ToStringStyle.SHORT_PREFIX_STYLE * ,调试的时候注意会自动取所有引用的值,会触发所有的Hibernate的延迟加载, * 如果遇到性能问题,必须覆盖这个默认的toString方法的实现,或者避免调用这个默认的toString方法。 * @return String */ public String toString() { ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); for (Field field : getClass().getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; } String name = field.getName(); if ("log".equals(name) || "serialVersionUID".equals(name)) { continue; } Object obj = ModelUtils.getProperty(this, name); if (obj instanceof AbstractPersistentCollection) { continue; } if (obj instanceof Calendar) { obj = DateTimeUtils.calendar2StrDateTime((Calendar) obj); } tsb.append(name, obj); } return tsb.toString(); } /**提供默认的clone方法的实现,不支持深层复制 * @return Object */ public E clone() { try { return (E) super.clone(); } catch (CloneNotSupportedException ex) { throw new IllegalArgumentException(ex.getMessage()); } } /**提供simple的clone方法的实现,不复制Hibernate代理对象 * @return Object */ public Object cloneSimple() { Object obj = ModelUtils.newInstance(getClass()); Field[] fields = getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { if (Modifier.isStatic(fields[i].getModifiers())) { continue; } String name = fields[i].getName(); if ("serialVersionUID".equals(name)) { continue; } Object fieldObj = ModelUtils.getProperty(this, name); if (fieldObj instanceof AbstractPersistentCollection || fieldObj instanceof BaseModel) { continue; } ModelUtils.setProperty(obj, name, fieldObj); } return obj; } }