前言:
最近在忙的一个项目是建立在Liferay Enterprise Portal上的,设计的几张数据表要与已有的Portal数据库中的User_表有级联关系。之前从Liferay的官方网站上了解到Liferay的Portal持久化都是通过Hibernate来实现,故对其实现的方法产生了小小的兴趣(因为我的数据表也打算通过Hibernate的O/R映射来实现,代码中难免要使用Portal的类com.liferay.portal.model.User)。
正文:
其实了解各种实现的方法,最好的莫过于读源码。(只要你有这个耐心)
我开始只想通过userId得到User对象,关于User对象的各种相关的类都在包com.liferay.portal.ejb里,你可以看到User开头的类有一堆,呵呵,其实我们这里只要涉及几个重要的类:
UserHBM.java 这个是User类的一个翻版,里面的信息和User里的信息基本一致(没仔细看),Portal也是通过这个类来映射数据库的User_表的。
UserPool.java 这个是一个与Cache相关的类,可不关心,并不影响理解。
UserManager.java 定义了与User相关的一组接口,对一些重要属性如Group,Role等的添加删除等。
UserManagerImpl.java 实现了UserManager接口,并继承了PrincipalBean.java。
UserUtil.java 个人觉得有点象实体bean的变体,里面有create,remove,update等方法,还有一些查找方法。
UserPersistence.java 这个里面是具体数据库的实现方法,UserUtil都是调用这个类的方法。
让我们先看看UserManagerImpl.java中关于得到User的代码,源码第400行
public User getUserById(String userId)
throws PortalException, SystemException {
userId = userId.trim().toLowerCase();
User user = UserUtil.findByPrimaryKey(userId);
if (getUserId().equals(userId) ||
hasAdministrator(user.getCompanyId())) {
return user;
}
else {
return (User)user.getProtected();
}
}
然后再看UserUtil.java的749行
protected static com.liferay.portal.model.User findByPrimaryKey(
java.lang.String userId)
throws com.liferay.portal.NoSuchUserException,
com.liferay.portal.SystemException {
UserPersistence persistence = (UserPersistence)InstancePool.get(PERSISTENCE);
return persistence.findByPrimaryKey(userId);
}
再找UserPersistence.java的3026行
protected com.liferay.portal.model.User findByPrimaryKey(String userId)
throws NoSuchUserException, SystemException {
com.liferay.portal.model.User user = UserPool.get(userId);
Session session = null;
try {
if (user == null) {
session = openSession();
UserHBM userHBM = (UserHBM)session.load(UserHBM.class, userId);
user = UserHBMUtil.model(userHBM);
}
return user;
}
catch (HibernateException he) {
if (he instanceof ObjectNotFoundException) {
throw new NoSuchUserException(userId.toString());
}
else {
throw new SystemException(he);
}
}
finally {
HibernateUtil.closeSession(session);
}
}
看完上面这些代码是不是就明白Portal是怎么通过userId得到User对象的?上面一段代码中红色的那句用过hibernate的人都会很熟悉,通过主键得到对象。
我们再深入一下,看一下BasePersistence.java,这个是UserPersistence.java的父类,上面代码中openSession()在这个类里定义。
public class BasePersistence {
protected Session openSession() throws HibernateException {
return HibernateUtil.openSession(getHibernateConfigurationClassName());
}
protected Dialect getDialect() {
return HibernateUtil.getDialect(getHibernateConfigurationClassName());
}
protected String getHibernateConfigurationClassName() {
return HibernateConfiguration.class.getName();
}
}
再看com.liferay.portal.util.HibernateUtil.java的63行
public static Session openSession(String className)
throws HibernateException {
SessionConfiguration config =
_getSessionConfigurationInstance(className);
return config.openSession();
}
com.liferay.util.dao.hibernate.SessionConfiguration.java是一个抽象类,让我直接看其子类com.liferay.portal.util.HibernateConfiguration.java
public class HibernateConfiguration extends SessionConfiguration {
public void init() {
try {
ClassLoader classLoader = getClass().getClassLoader();
Configuration cfg = new Configuration();
String[] configs = StringUtil.split(
SystemProperties.get("hibernate.configs"));
for (int i = 0; i < configs.length; i++) {
try {
InputStream is =
classLoader.getResourceAsStream(configs[i]);
if (is != null) {
cfg = cfg.addInputStream(is);
is.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
cfg.setProperties(SystemProperties.getProperties());
setSessionFactory(cfg.buildSessionFactory());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
上面代码中的红色部分是从系统的properties文件中读取一些值,实际上是调用portal-ejb/system.properties文件,从这个文件的第94行就可以发现一些Hibernate用来做O/R mapping的文件。代码中通过InputStream方式把这些mapping files加到Configuration中去。
大家可以去看一下这些mapping files是不是我们所熟悉的****.hbm.xml的格式?
后记:
读了一早上的源码,写了一个小时的blog,无非是想切实的解决一个问题。通过读源码可以了解一些机制,也可以了解一些设计思想,对于每一个学习者都是有益的。从开始不知道用什么方法好,就去找admin portlet里找JSP(list-users.jsp),里面有一些相关的用户管理的方法(User[] users = (User[])CompanyLocalManagerUtil.getUsers(company.getCompanyId()).toArray(new User[0]);),从中找到一个得到所有User的方法,也让我联想的去找一些相关的类,后来我就找到UserManagerUtil.java。这个过程是猜测到证实的过程,当你的猜测得到证实的时候,当你发现那个经过多层包装的你熟悉的接口方法的时候,那种感觉是快乐的,满足的。