两个蝴蝶飞 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;
}
}