前几天搞了一个BUG,吧精力耗尽,也激发了我对Liferay这个框架内部的探究欲望。所以这几天端午节准备对Liferay框架启动过程进行深入研究,来满足自己的好奇心。
当我们在地址栏中访问http://localhost:8080时,因为Liferay应用本质上也是一个web应用,所以它会去找ROOT应用的web.xml,因为定义了<welcome-file-list>:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
所以,它会去找index.jsp:
...
<%
String redirect = null;
LayoutSet layoutSet = (LayoutSet)request.getAttribute(WebKeys.VIRTUAL_HOST_LAYOUT_SET);
if (layoutSet != null) {
long defaultPlid = LayoutLocalServiceUtil.getDefaultPlid(layoutSet.getGroupId(), layoutSet.isPrivateLayout());
if (defaultPlid != LayoutConstants.DEFAULT_PLID) {
Layout layout = LayoutLocalServiceUtil.getLayout(defaultPlid);
ServicePreAction servicePreAction = (ServicePreAction)InstancePool.get(ServicePreAction.class.getName());
ThemeDisplay themeDisplay = servicePreAction.initThemeDisplay(request, response);
redirect = PortalUtil.getLayoutURL(layout, themeDisplay);
}
else {
redirect = PortalUtil.getPathMain();
}
else {
redirect = PortalUtil.getHomeURL(request);
if (!request.isRequestedSessionIdFromCookie()) {
redirect = PortalUtil.getURLWithSessionId(redirect, session.getId());
response.setHeader(HttpHeaders.LOCATION, redirect);
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
%>
<html>
<head>
<title></title>
<meta content="1; url=<%= redirect %>" http-equiv="refresh" />
</head>
<body onload="javascript:location.replace('<%= redirect %>')">
</body>
</html>
其中,最值得看的就是<body onload="javascript:location.replace...),它会在DOM树加载完毕之后触发,那么我们感兴趣的是,这个<%=redirect%>到底是什么呢?
寻找<%=redirect%>的值
为此,我们去看上面那段代码,因为第一次登录,所以什么用户信息都没有,所以实际上走的是以下的代码段:
然后这段代码会调用PortalUtil中的:
public static String getPathMain() {
return getPortal().getPathMain();
然后调用PortalImpl类中的:
public String getPathMain() {
return _pathMain;
而这个_pathMain是由该类中以下代码提供的,在PortalImpl构造器中:
// Paths
_pathProxy = PropsValues.PORTAL_PROXY_PATH;
_pathContext = ContextPathUtil.getContextPath(PropsValues.PORTAL_CTX);
_pathContext = _pathProxy.concat(_pathContext);
_pathFriendlyURLPrivateGroup =
_pathContext + _PRIVATE_GROUP_SERVLET_MAPPING;
_pathFriendlyURLPrivateUser =
_pathContext + _PRIVATE_USER_SERVLET_MAPPING;
_pathFriendlyURLPublic = _pathContext + _PUBLIC_GROUP_SERVLET_MAPPING;
_pathImage = _pathContext + PATH_IMAGE;
_pathMain = _pathContext + PATH_MAIN;
// Groups
所以_pathMain为_pathContext+PATH_MAIN ,我们依次来解析:
解析 _pathContext:
对于_pathContext,它是ContextPathUtil.getContextPath(PropsValues.PORTAL_CTX);
其中PropsValues.PORTAL_CTX是:
public static final String PORTAL_CTX = PropsUtil.get(PropsKeys.PORTAL_CTX);
它会去找PropsKeys接口中的常量定义:
public static final String PORTAL_CTX = "portal.ctx";
然后找到并替换之后,去执行PropsUtil.get("portal.ctx");
public static String get(String key) {
return _instance._get(key);
它会访问
private String _get(String key) {
return _getConfiguration().get(key);
这段代码最终会访问配置文件,然后读取key-value对到Configuration中,我们在portal.properties中找到了portal.ctx的定义:
##
## Portal Context
#
# Specify the path of the portal servlet context. This is needed because
# javax.servlet.ServletContext did not have access to the context path until
# Java EE 5.
# Set this property if you deploy the portal to another path besides root.
portal.ctx=/
所以portal.ctx=/
解析PATH_MAIN:
它在Portal接口中有定义:
public static final String PATH_MAIN = "/c";
所以综上所述,在PortalImpl构造器中的_pathMain = _pathContext + PATH_MAIN="/"+"/c"="//c"
它就是<%=redirect%>的值。
所以当index.jsp中DOM树加载完毕之后,它会去执行:
<body onload="javascript:location.replace('//c')">
而对于location.replace(String)方法,它的作用是启动一个不可逆的重定向:参见下面这篇文章:
<a href="http://www.roseindia.net/javascript/javascript-location-replace.shtml">http://www.roseindia.net/javascript/javascript-location-replace.shtml</a>
所以我们现在知道,在DOM树加载完毕后,它吧请求发送到了http://localhost:8080/c 这个位置。
之后的步骤见下一篇博客
本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/905695,如需转载请自行联系原作者