CAS单点登录开源框架解读(四)--扩展--登录页隐藏属性"execution"值如何产生
这里写自定义目录标题登录流程配置cas-servlet.xml登录流程之执行实现FlowExecutorImpl和FlowExecutionImpl登录流程之Flow和状态类State登录流程之Transition过渡流程判断和ViewState页面初始化准备登录流程配置cas-servlet.xml在登录流程发起之前,先看一些cas是如何通过配置加载到login-webflow.xml这个登..
登录流程配置cas-servlet.xml
在登录流程发起之前,先看一些cas是如何通过配置加载到login-webflow.xml这个登录流程的。具体可以看一些cas-servlet.xml这个配置。
<bean id="loginHandlerAdapter" class="org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter"
p:supportedFlowId="login" p:flowExecutor-ref="loginFlowExecutor" p:flowUrlHandler-ref="loginFlowUrlHandler"/>
<bean id="loginFlowUrlHandler" class="org.jasig.cas.web.flow.CasDefaultFlowUrlHandler"/>
<bean name="loginFlowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl"
c:definitionLocator-ref="loginFlowRegistry"
c:executionFactory-ref="loginFlowExecutionFactory"
c:executionRepository-ref="loginFlowExecutionRepository"/>
<bean name="loginFlowExecutionFactory" class="org.springframework.webflow.engine.impl.FlowExecutionImplFactory"
p:executionKeyFactory-ref="loginFlowExecutionRepository"/>
<bean id="loginFlowExecutionRepository" class=" org.jasig.spring.webflow.plugin.ClientFlowExecutionRepository"
c:flowExecutionFactory-ref="loginFlowExecutionFactory"
c:flowDefinitionLocator-ref="loginFlowRegistry"
c:transcoder-ref="loginFlowStateTranscoder"/>
<bean id="loginFlowStateTranscoder" class="org.jasig.spring.webflow.plugin.EncryptedTranscoder"
c:cipherBean-ref="loginFlowCipherBean" />
注意上面配置中的loginFlowExecutor这个bean的配置,其中的属性loginFlowExecutionFactory正是决定启动login-webflow.xml相关配置的bean,那么loginFlowExecutionFactory这个bean是在哪里配置的呢?这个配置是在webflowContext.xml中进行了相关配置。
<webflow:flow-registry id="loginFlowRegistry" flow-builder-services="builder" base-path="/WEB-INF/webflow">
<webflow:flow-location-pattern value="/login/*-webflow.xml"/>
</webflow:flow-registry>
从上面我们可以知道这个登录的流程的启动大致是通过bean的加载,如何到login-webflow.xml这个配置属性中的。
登录流程之执行实现FlowExecutorImpl和FlowExecutionImpl
有了上面的对于这些配置文件的了解,那么我们就分析对应的代码是如何启动相关的登录流程。
流程启动最终的实现是由FlowExecutorImpl这个类发起的具体代码如下所示:
org.springframework.webflow.executor.FlowExecutorImpl
public FlowExecutionResult launchExecution(String flowId, MutableAttributeMap<?> input, ExternalContext context)
throws FlowException {
try {
if (logger.isDebugEnabled()) {
logger.debug("Launching new execution of flow '" + flowId + "' with input " + input);
}
//加载web.xml中相关配置信息
ExternalContextHolder.setExternalContext(context);
FlowDefinition flowDefinition = definitionLocator.getFlowDefinition(flowId);
//创建流程执行器
FlowExecution flowExecution = executionFactory.createFlowExecution(flowDefinition);
//流程执行器启动,请关注这里的start方法,后续的一些属性都会在start后加入,包括execution这个属性的值
flowExecution.start(input, context);
if (!flowExecution.hasEnded()) {
FlowExecutionLock lock = executionRepository.getLock(flowExecution.getKey());
lock.lock();
try {
executionRepository.putFlowExecution(flowExecution);
} finally {
lock.unlock();
}
return createPausedResult(flowExecution);
} else {
return createEndResult(flowExecution);
}
} finally {
ExternalContextHolder.setExternalContext(null);
}
}
通过FlowExecutorImpl启动后,后续调用的是FlowExecutionImpl,注意这两个类的区别,虽然两个类都是在spring-webflow包中。
org.springframework.webflow.engine.impl.FlowExecutionImpl
public void start(MutableAttributeMap<?> input, ExternalContext externalContext) throws FlowExecutionException,
IllegalStateException {
………………
try {
//继续启动
start(flow, input, requestContext);
} catch (FlowExecutionException e) {
handleException(e, requestContext);
} catch (Exception e) {
handleException(wrap(e), requestContext);
} finally {
saveFlashMessages(requestContext);
if (isActive()) {
try {
listeners.firePaused(requestContext);
} catch (Throwable e) {
logger.error("FlowExecutionListener threw exception", e);
}
}
try {
listeners.fireRequestProcessed(requestContext);
} catch (Throwable e) {
logger.error("FlowExecutionListener threw exception", e);
}
RequestContextHolder.setRequestContext(null);
}
}
void start(Flow flow, MutableAttributeMap<?> input, RequestControlContext context) {
…………
StateManageableMessageContext messageContext = (StateManageableMessageContext) context.getMessageContext();
messageContext.setMessageSource(flow.getApplicationContext());
listeners.fireSessionStarting(context, session, input);
//注意这里的启动
flow.start(context, input);
listeners.fireSessionStarted(context, session);
}
登录流程之Flow和状态类State
在经过了各种流程执行器之后,我们来到了最终的流程Flow下,并最终进入相关状态的条件判断
org.springframework.webflow.engine.Flow
public void start(RequestControlContext context, MutableAttributeMap<?> input) throws FlowExecutionException {
assertStartStateSet();
createVariables(context);
if (inputMapper != null) {
MappingResults results = inputMapper.map(input, context);
if (results != null && results.hasErrorResults()) {
throw new FlowInputMappingException(getId(), results);
}
}
startActionList.execute(context);
//进入状态的判断
startState.enter(context);
}
org.springframework.webflow.engine.State
public final void enter(RequestControlContext context) throws FlowExecutionException {
if (logger.isDebugEnabled()) {
logger.debug("Entering state '" + getId() + "' of flow '" + getFlow().getId() + "'");
}
context.setCurrentState(this);
doPreEntryActions(context);
entryActionList.execute(context);
//由具体的实现类去执行具体的进入方法
doEnter(context);
}
注意这里的实现类都是基于TransitionableState这个抽象类进行实现的,因为我们可以在login-webflow.xml中看到对于表达式expression配置之后的判断都是由transition决定跳转到具体的state。
基于TransitionableState抽象类的实现类包括:
1、org.springframework.webflow.engine.ActionState
2、org.springframework.webflow.engine.DecisionState
3、org.springframework.webflow.engine.SubflowState
4、org.springframework.webflow.engine.ViewState
登录流程之Transition过渡流程判断和ViewState页面初始化准备
在跳转到ViewState状态之前,还需要由 org.springframework.webflow.engine.Transition类来进行判别,具体是如何进行的看下面的代码。
org.springframework.webflow.engine.Transition
//已去掉日志相关代码
public boolean execute(State sourceState, RequestControlContext context) throws FlowExecutionException {
if (canExecute(context)) {
context.setCurrentTransition(this);
if (targetStateResolver != null) {
//获取到目标的流程状态
State targetState = targetStateResolver.resolveTargetState(this, sourceState, context);
if (targetState != null) {
if (sourceState != null) {
if (sourceState instanceof TransitionableState) {
((TransitionableState) sourceState).exit(context);
}
}
//由目标的流程状态决定进入不同的状态处理,这里的流程状态为ViewState时就会进入处理相关的前端页面属性信息
targetState.enter(context);
return true;
}
}
}
return false;
}
在状态选择为ViewState时,我们看一下这里面是如何去处理页面相关属性的,特别是如何产生execution的。需要特别注意的是ViewState类中doEnter()方法中是如何创建FlowExecutionKey的。
org.springframework.webflow.engine.ViewState
protected void doEnter(RequestControlContext context) throws FlowExecutionException {
//特别注意这里,这里是关联了FlowExecutionKey,FlowExecutionKey才是产最终的execution类,其实最终的实现还是在FlowExecutionImpl中的assignKey()方法
context.assignFlowExecutionKey();
ExternalContext externalContext = context.getExternalContext();
if (externalContext.isResponseComplete()) {
if (!externalContext.isResponseCompleteFlowExecutionRedirect()) {
clearFlash(context);
}
} else {
if (shouldRedirect(context)) {
context.getExternalContext().requestFlowExecutionRedirect();
if (popup) {
context.getExternalContext().requestRedirectInPopup();
}
} else {
View view = viewFactory.getView(context);
context.setCurrentView(view);
//注意这里的解析
render(context, view);
}
}
}
private void render(RequestControlContext context, View view) throws ViewRenderingException {
……
//设置相关的前端页面
context.viewRendering(view);
renderActionList.execute(context);
try {
//具体页面上相关属性的提取和设置
view.render();
} catch (IOException e) {
throw new ViewRenderingException(getOwner().getId(), getId(), view, e);
}
clearFlash(context);
context.getExternalContext().recordResponseComplete();
context.viewRendered(view);
}
view.render()方法的view最终调用的是org.springframework.webflow.mvc.view.AbstractMvcView类,我们来看一下这个类中是如何具体处理相关的属性的。
public void render() throws IOException {
Map<String, Object> model = new HashMap<String, Object>();
//flowScopes()方法会提取requestContext中所有的相关属性,具体代码可自行查看
model.putAll(flowScopes());
exposeBindingModel(model);
//存入相关flowRequestContext属性值
model.put("flowRequestContext", requestContext);
FlowExecutionKey key = requestContext.getFlowExecutionContext().getKey();
**//终于看到了flowExecutionKey这个属性,然后存入对应的值**
if (key != null) {
model.put("flowExecutionKey", requestContext.getFlowExecutionContext().getKey().toString());
model.put("flowExecutionUrl", requestContext.getFlowExecutionUrl());
}
model.put("currentUser", requestContext.getExternalContext().getCurrentUser());
try {
if (logger.isDebugEnabled()) {
logger.debug("Rendering MVC [" + view + "] with model map [" + model + "]");
}
//最终解析到具体的页面,由org.springframework.webflow.mvc.servlet.ServletMvcView实现
doRender(model);
} catch (IOException e) {
throw e;
} catch (Exception e) {
IllegalStateException ise = new IllegalStateException("Exception occurred rendering view " + view);
ise.initCause(e);
throw ise;
}
}
通过上面的一系列的代码查看,我们知道最终execution前端的属性这个值是在哪里产生,并放入对应的流程中,返回前端页面。
更多推荐
所有评论(0)