EL(Expression Language)隐式对象提供了简化在 JSP 页面中访问和操作常用数据的方式。这些隐式对象背后有复杂的机制来实现数据的动态绑定和作用域管理。以下是 EL 隐式对象的工作原理及其实现细节。
EL 隐式对象的实现原理
EL 隐式对象的实现主要依赖于 javax.el
包中的接口和类,如 ELContext
、ELResolver
、VariableMapper
等。EL 通过这些机制将 JSP 页面中的变量名绑定到实际的对象或数据上。
1. ELContext
ELContext
是 EL 表达式求值时的上下文对象,提供了访问 ELResolver
和 VariableMapper
的方法。在 JSP 运行时,ELContext
包含了当前的上下文信息,如请求、响应、会话等。
2. ELResolver
ELResolver
是一个接口,用于解析 EL 表达式中的变量。EL 通过调用 ELResolver
的 getValue()
方法来获取表达式的值。多个 ELResolver
可以组成一个链,按顺序解析变量。
java
public abstract class ELResolver {
public abstract Object getValue(ELContext context, Object base, Object property);
}
解释: 当 EL 表达式如 ${param.name}
被求值时,ELResolver
会按顺序查找匹配的变量,并返回其值。
3. VariableMapper
VariableMapper
管理 EL 表达式中的变量和它们的绑定。它提供了 resolveVariable
方法,用于将变量名绑定到实际的表达式或对象。
java
public abstract class VariableMapper {
public abstract ValueExpression resolveVariable(String variable);
}
解释: VariableMapper
允许在 EL 表达式中动态绑定变量,提供了灵活的变量解析机制。
EL 隐式对象的实现
以下是常见的 EL 隐式对象及其实现方式:
1. pageScope
、requestScope
、sessionScope
、applicationScope
这些隐式对象是 Map
实现的,提供对不同作用域变量的访问。它们通过 PageContext
的相应方法实现,如 getAttribute
。
java
// 访问不同作用域的变量
public class ScopeELResolver extends ELResolver {
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
String varName = (String) property;
PageContext pageContext = (PageContext) context.getContext(PageContext.class);
// 检查页面范围
Object value = pageContext.getAttribute(varName, PageContext.PAGE_SCOPE);
if (value == null) {
// 检查请求范围
value = pageContext.getAttribute(varName, PageContext.REQUEST_SCOPE);
if (value == null) {
// 检查会话范围
value = pageContext.getAttribute(varName, PageContext.SESSION_SCOPE);
if (value == null) {
// 检查应用范围
value = pageContext.getAttribute(varName, PageContext.APPLICATION_SCOPE);
}
}
}
return value;
}
return null;
}
}
解释: ScopeELResolver
通过检查 PageContext
的不同作用域来解析变量值。
2. param
和 paramValues
param
是一个 Map
,提供对请求参数的访问,paramValues
提供对请求参数数组的访问。这是通过 HttpServletRequest
实现的。
java
// 访问请求参数
public class ParamELResolver extends ELResolver {
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
String paramName = (String) property;
HttpServletRequest request = (HttpServletRequest) context.getContext(HttpServletRequest.class);
return request.getParameter(paramName);
}
return null;
}
}
解释: ParamELResolver
通过调用 HttpServletRequest
的 getParameter
方法访问请求参数。
3. cookie
cookie
隐式对象实际是一个Map<String,Cookie>
,提供对 Cookie 的访问。每个键是 Cookie 的名称,值是 Cookie
对象。
java
// 访问 Cookie
public class CookieELResolver extends ELResolver {
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
String cookieName = (String) property;
HttpServletRequest request = (HttpServletRequest) context.getContext(HttpServletRequest.class);
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
}
return null;
}
}
解释: CookieELResolver
遍历请求中的 Cookie 数组,匹配名称后返回 Cookie
对象。
EL 表达式的求值过程
- 解析表达式 : EL 表达式如
${userName}
被 JSP 引擎解析。 - 查找变量 : EL 引擎使用
ELResolver
和VariableMapper
查找变量。 - 返回值 : 如果找到匹配的变量,返回其值;否则返回
null
或默认值。
示例: 自定义 EL 解析器
你可以自定义 EL 解析器来扩展 EL 的功能。例如,实现一个自定义 ELResolver
来访问自定义数据源。
java
public class CustomELResolver extends ELResolver {
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
// 自定义解析逻辑
if ("customData".equals(property)) {
return "Custom Data Value";
}
}
return null;
}
}
解释: CustomELResolver
自定义了解析逻辑,允许 EL 表达式访问自定义数据源。
总结
EL 隐式对象的工作原理依赖于 ELContext
、ELResolver
和 VariableMapper
等核心组件,通过这些组件,EL 可以动态地解析和绑定 JSP 页面中的变量和数据。隐式对象提供了对常用数据(如请求参数、会话属性、Cookie 等)的简化访问,从而提高 JSP 页面的开发效率和代码的可读性。