登录流程配置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前端的属性这个值是在哪里产生,并放入对应的流程中,返回前端页面。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐