日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

struts2 处理请求流程分析(结合源码)

發布時間:2024/4/17 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 struts2 处理请求流程分析(结合源码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://zhxing.iteye.com/blog/541059

struts2 源碼版本2.0.11.1

本文是綜合網上部分人的分析成果,然后再自己結合源碼進行的,分析中如有錯誤,請指正。

?? 從struts2 中的web.xml的啟動配置可以看出,首先分析的是FilterDispatcher 這個過濾器類。

?

1、過濾器的初始化方法 void init(FilterConfig filterConfig)

Java代碼 //初始化方法 public void init(FilterConfig filterConfig) throws ServletException {this.filterConfig = filterConfig;//獲得默認的參數,創建dispathcher 對象dispatcher = createDispatcher(filterConfig);dispatcher.init();String param = filterConfig.getInitParameter("packages");String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";if (param != null) {packages = param + " " + packages;}this.pathPrefixes = parse(packages);}

?

??? 1.1、createDispatcher(filterConfig);方法,該方法的目的是創建Dispathcher 對象

?

Java代碼 protected Dispatcher createDispatcher(FilterConfig filterConfig) {//讀取相應過濾器的web.xml 配置Map<String,String> params = new HashMap<String,String>();for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {String name = (String) e.nextElement();String value = filterConfig.getInitParameter(name);params.put(name, value);}//可以看出Dispatcher 類包裝了ServletContext 和過濾器的web.xml 配置return new Dispatcher(filterConfig.getServletContext(), params);}

?

?

? 1.2、dispatcher.init();方法,該方法對dispatcher進行了一系列的初始化工作,這個工作很重要也有點復雜,具體每個初始化的工作的流程怎樣,待有空閑的時候再繼續分析,網上也有人已經分析過了,如果有興趣可參照:http://zddava.iteye.com/blog/211795

?

Java代碼 public void init() {if (configurationManager == null) {configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);}//讀取properties信息,默認的default.propertiesinit_DefaultProperties(); // [1]//讀取xml配置文件,默認的struts-default.xml,struts-plugin.xml,struts.xmlinit_TraditionalXmlConfigurations(); // [2]//讀取用戶自定義的struts.properties init_LegacyStrutsProperties(); // [3]//讀取FilterDispatcher的配置中所定義的actionPackages屬性,傳說中的Struts 2 零配置所謂的零配置init_ZeroConfiguration(); // [4]//自定義的configProviders init_CustomConfigurationProviders(); // [5]//該功能全面被注釋init_MethodConfigurationProvider();//載入FilterDispatcher傳進來的initParams init_FilterInitParameters() ; // [6]//將配置文件中的bean與具體的類映射 init_AliasStandardObjects() ; // [7]//構建一個用于依賴注射的Container對象 //在這里面會循環調用上面七個ConfigurationProvider的register方法 //其中的重點就是DefaultConfiguration的#reload()方法 Container container = init_PreloadConfiguration();init_CheckConfigurationReloading(container);init_CheckWebLogicWorkaround(container);}

?

?? 1.3、String param = filterConfig.getInitParameter("packages"); 以下的代碼。這個步驟載入了packages標簽下定義的靜態資源。 讀取web.xml中 的下面的配置路徑還有org.apache.struts2.static,template,org.apache.struts2.interceptor.debugging這三個包空間下邊的資源也會作為靜態資源載入。

Xml代碼 <filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class><init-param><param-name>packages</param-name><param-value>cn.static.resource</param-value></init-param></filter>

?

? ? 1.4、this.pathPrefixes = parse(packages);這個步驟是對packages 進行解析的。

Java代碼 protected String[] parse(String packages) {if (packages == null) {return null;}List<String> pathPrefixes = new ArrayList<String>();StringTokenizer st = new StringTokenizer(packages, ", \n\t");while (st.hasMoreTokens()) {String pathPrefix = st.nextToken().replace('.', '/');if (!pathPrefix.endsWith("/")) {pathPrefix += "/";}pathPrefixes.add(pathPrefix);}return pathPrefixes.toArray(new String[pathPrefixes.size()]);}

?

?

2、過濾器中的doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 方法

?

?

?

2.1、request = prepareDispatcherAndWrapRequest(request, response);分析

???? 我們知道JSTL默認是從page,request,session,application這四個Scope逐次查找相應的EL表達式所對應的對象的值。那么如果要使用JSTL來讀取Action中的變量,就需要把Action中的變量,放到request域中才行Struts2,都使用另外一種整合方式:對HttpServletRequest進行裝飾(StrutsRequestWrapper )這個類會在Struts2初始化的時候,替換HttpServletRequest,運行于整個Struts2的運行過程中,當我們試圖調用request.getAttribute()的時候,就會執行上面的這個方法。(這是一個典型的裝飾器模式)在執行上面的方法時,會首先調用HttpServletRequest中原本的request.getAttribute(),如果沒有找到,它會繼續到ValueStack中去查找,而action在ValueStack中,所以action中的變量通過OGNL表達式,就能找到對應的值了。

?

Java代碼 protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException {//獲取dispatch 的單例類,是由LocalThread 保存的,保證線程的安全Dispatcher du = Dispatcher.getInstance();// Prepare and wrap the request if the cleanup filter hasn't already,// cleanup filter should be// configured first before struts2 dispatcher filter, hence when its// cleanup filter's turn,// static instance of Dispatcher should be null.if (du == null) {//如果為空的話,值保存進LocalThread 中Dispatcher.setInstance(dispatcher);// prepare the request no matter what - this ensures that the proper// character encoding// is used before invoking the mapper (see WW-9127)// request 編碼設置和response 本地化設置dispatcher.prepare(request, response);} else {dispatcher = du;}try {// Wrap request first, just in case it is multipart/form-data// parameters might not be accessible through before encoding// (ww-1278)//在這里就開始包裝request = dispatcher.wrapRequest(request, getServletContext());} catch (IOException e) {String message = "Could not wrap servlet request with MultipartRequestWrapper!";LOG.error(message, e);throw new ServletException(message, e);}return request;}

?

?簡單看下這個方法Dispatcher.getInstance();

Java代碼 private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>(); //other code public static Dispatcher getInstance() {return instance.get(); }

?

主要的包裝在此方法進行request = dispatcher.wrapRequest(request, getServletContext());

Java代碼 public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {// don't wrap more than once 如果已經包裝了,就不用再包裝了if (request instanceof StrutsRequestWrapper) {return request;}String content_type = request.getContentType();//非表單提交的request 封裝,主要是圖片上傳等 if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class);//如果是非表單提交則包裝成MultiPartRequestWrapperrequest = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext));} else {//如果是普通表單提交,在此包裝request = new StrutsRequestWrapper(request);}return request;}

?

2.2、mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());方法的分析

?? 這里的分析參照了:http://zddava.iteye.com/blog/215504

下面來看一下默認使用的ActionMapper實現DefaultActionMapper的#getMapping():

Java代碼 public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager) {ActionMapping mapping = new ActionMapping();// (1)String uri = getUri(request);// (2)uri = dropExtension(uri);// (3)if (uri == null) {return null;}parseNameAndNamespace(uri, mapping, configManager);// (4)handleSpecialParameters(request, mapping);// (5)if (mapping.getName() == null) {return null;}if (allowDynamicMethodCalls) {// (6)String name = mapping.getName();int exclamation = name.lastIndexOf("!");if (exclamation != -1) {mapping.setName(name.substring(0, exclamation));mapping.setMethod(name.substring(exclamation + 1));}}return mapping;}

?

主要有6處需要重點說明:

(1) 關于ActionMapping類,它內部封裝了如下5個字段:

Java代碼 private String name;// Action名private String namespace;// Action名稱空間private String method;// 執行方法private Map params;// 可以通過set方法設置的參數private Result result;// 返回的結果

?

這些在配置文件中都是可設置的,確定了ActionMapping類的各個字段的值,就可以對請求的Action進行調用了。

(2) String uri = getUri(request);

這個步驟用于獲取客戶端發送的請求的URI,源代碼如下:

Java代碼 String getUri(HttpServletRequest request) {// handle http dispatcher includes.String uri = (String) request.getAttribute("javax.servlet.include.servlet_path");if (uri != null) {return uri;}uri = RequestUtils.getServletPath(request);if (uri != null && !"".equals(uri)) {return uri;}uri = request.getRequestURI();return uri.substring(request.getContextPath().length());}

?

???? 這個方法首先判斷請求是否來自于一個jsp的include,如果是,那么請求的"javax.servlet.include.servlet_path"屬性可以獲得include的頁面uri,否則通過一般的方法獲得請求的uri,最后返回去掉ContextPath的請求路徑,比如http://127.0.0.1:8087/test/jsp/index.jsp?param=1,返回的為/jsp/index.jsp。去掉了ContextPath和查詢字符串等。

(3) uri = dropExtension(uri); 負責去掉Action的"擴展名"(默認為"action"),源代碼如下:

?

Java代碼 String dropExtension(String name) {//extensions 為struts2 的后綴名,可有多個,默認為action// List extensions = new ArrayList() {{ add("action");}};if (extensions == null) {return name;}Iterator it = extensions.iterator();//分別遍歷后去掉后綴名while (it.hasNext()) {String extension = "." + (String) it.next();if (name.endsWith(extension)) {name = name.substring(0, name.length() - extension.length());return name;}}return null;}

?

注意,這個步驟對于不是以特地擴展名結尾的請求會返回一個null的uri,進而#getMapping()也會返回null,FilterDispatcher的#doFilter()就會把這次請求當作一個普通請求對待了。

(4) parseNameAndNamespace(uri, mapping, configManager);

此方法用于解析Action的名稱和命名空間,并賦給ActionMapping對象。源代碼如下:

Java代碼 void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {String namespace, name;// 例如 http://127.0.0.1:8087/teststruts/namespace/name.action?param=1 // dropExtension()后,獲得uri為/namespace/name int lastSlash = uri.lastIndexOf("/");if (lastSlash == -1) {namespace = "";name = uri;} else if (lastSlash == 0) {namespace = "/";name = uri.substring(lastSlash + 1);} else if (alwaysSelectFullNamespace) {// alwaysSelectFullNamespace默認為false,代表是否將最后一個"/"前的字符全作為名稱空間。namespace = uri.substring(0, lastSlash);// 獲得字符串 namespacename = uri.substring(lastSlash + 1);// 獲得字符串 name} else {// 例如 http://127.0.0.1:8087/teststruts/namespace1/namespace2/actionname.action?param=1// dropExtension()后,獲得uri為/namespace1/namespace2/actionname Configuration config = configManager.getConfiguration();String prefix = uri.substring(0, lastSlash);// 獲得 /namespace1/namespace2namespace = "";// 如果配置文件中有一個包的namespace是 /namespace1/namespace2,那么namespace為/namespace1/namespace2,name為actionname// 如果配置文件中有一個包的namespace是 /namespace1,那么namespace為/namespace1,name為/namespace2/actionnamefor (Iterator i = config.getPackageConfigs().values().iterator(); i.hasNext();) {String ns = ((PackageConfig) i.next()).getNamespace();if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {if (ns.length() > namespace.length()) {namespace = ns;}}}name = uri.substring(namespace.length() + 1);}if (!allowSlashesInActionNames && name != null) {// allowSlashesInActionNames代表是否允許"/"出現在Action的名稱中,默認為falseint pos = name.lastIndexOf('/');if (pos > -1 && pos < name.length() - 1) {name = name.substring(pos + 1);}}// 以 name = /namespace2/actionname 為例,經過這個if塊后,name = actionnamemapping.setNamespace(namespace);mapping.setName(name);}

?

(5) handleSpecialParameters(request, mapping); 此方法用于處理Struts框架定義的四種特殊的prefix:

下邊是struts2的javadoc里提供的例子:

Method prefix:調用baz的另外一個方法"anotherMethod"而不是"execute"

Html代碼 <a:form action="baz"><a:textfield label="Enter your name" name="person.name"/><a:submit value="Create person"/><a:submit name="method:anotherMethod" value="Cancel"/></a:form>

?

Action prefix:調用anotherAction的"execute"

Html代碼 <a:form action="baz"><a:textfield label="Enter your name" name="person.name"/><a:submit value="Create person"/><a:submit name="action:anotherAction" value="Cancel"/></a:form>

?

Redirect prefix:將請求重定向,下例中為定向到google

Html代碼 <a:form action="baz"><a:textfield label="Enter your name" name="person.name"/><a:submit value="Create person"/><a:submit name="redirect:www.google.com" value="Cancel"/></a:form>

?

Redirect-action prefix:重定向action,下例中為定向到dashboard.action

Html代碼 <a:form action="baz"><a:textfield label="Enter your name" name="person.name"/><a:submit value="Create person"/><a:submit name="redirect-action:dashboard" value="Cancel"/></a:form>

?

handleSpecialParameters的源代碼如下:

Java代碼 public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) {Set<String> uniqueParameters = new HashSet<String>();Map parameterMap = request.getParameterMap();for (Iterator iterator = parameterMap.keySet().iterator(); iterator.hasNext();) {String key = (String) iterator.next();if (key.endsWith(".x") || key.endsWith(".y")) {// 去掉圖片按鈕的位置信息,具體情況我也不是很了解key = key.substring(0, key.length() - 2);}// 處理四種特殊的prefix:Method prefix,Action prefix,Redirect prefix,Redirect-action prefixif (!uniqueParameters.contains(key)) {ParameterAction parameterAction = (ParameterAction) prefixTrie.get(key);if (parameterAction != null) {// 當發現某種特殊的predix時parameterAction.execute(key, mapping);// 調用它的execute方法,在DefaultActionMapper的構造函數中定義uniqueParameters.add(key);// 下邊已經break了為什么還要把key加入到排重的Set里呢??break;}}}}

?(6) 處理調用的不是execute方法的情況:
Struts框架也可以處理"name!method"形式的action調用,碰到這種情況,在此處將name和method分別解析出來然后賦給ActionMapping對象。

?

?

2.3、dispatcher.serviceAction(request, response, servletContext, mapping);方法分析

Java代碼 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping) throws ServletException {//包裝了Http的四個作用域,extraContext 保存了所有的servlet 容器的作用域和struts2 包裝的容器作用域Map<String, Object> extraContext = createContextMap(request, response, mapping, context);// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action//如果之前有ValueStack 值棧存在,則用這個,否則創建一個新的,保存在extraContext 中ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);if (stack != null) {extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));}String timerKey = "Handling request from Dispatcher";try {UtilTimerStack.push(timerKey);//獲得action 的配置信息String namespace = mapping.getNamespace();String name = mapping.getName();String method = mapping.getMethod();Configuration config = configurationManager.getConfiguration();//創建一個ActionProxyActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, extraContext, true, false);//如果method 為空,則設為“excue”proxy.setMethod(method);//保存值棧供struts2 使用request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());// if the ActionMapping says to go straight to a result, do it!//如果result 不為空的話,進行調轉if (mapping.getResult() != null) {Result result = mapping.getResult();//注入的是ActionInvactionresult.execute(proxy.getInvocation());} else {proxy.execute();}// If there was a previous value stack then set it back onto the requestif (stack != null) {request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);}} catch (ConfigurationException e) {LOG.error("Could not find action or result", e);sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);} catch (Exception e) {throw new ServletException(e);} finally {UtilTimerStack.pop(timerKey);}}

?

??? (1)createContextMap(request, response, mapping, context);方法

Java代碼 public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,ActionMapping mapping, ServletContext context) {// request map wrapping the http request objectsMap requestMap = new RequestMap(request);// parameters map wrapping the http paraneters.Map params = null;if (mapping != null) {params = mapping.getParams();}Map requestParams = new HashMap(request.getParameterMap());if (params != null) {params.putAll(requestParams);} else {params = requestParams;}// session map wrapping the http sessionMap session = new SessionMap(request);// application map wrapping the ServletContextMap application = new ApplicationMap(context);//對上面的http 作用域包裝的map 進行封裝Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);//把mapping 也放進map 里extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);return extraContext;}

?? 由此可以看出struts2 對servlet 容器的作用域都進行包裝成相應的Map ,然后放在extraContext? 統一進行保存。

來看看extraContext? 這個map 里放的是全部servlet 容器作用域還有相應的struts2的包裝map,和 locale,從下面的源碼中可以看出。

Java代碼 public HashMap<String,Object> createContextMap(Map requestMap,Map parameterMap,Map sessionMap,Map applicationMap,HttpServletRequest request,HttpServletResponse response,ServletContext servletContext) {HashMap<String,Object> extraContext = new HashMap<String,Object>();extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));extraContext.put(ActionContext.SESSION, sessionMap);extraContext.put(ActionContext.APPLICATION, applicationMap);Locale locale;if (defaultLocale != null) {locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());} else {locale = request.getLocale();}extraContext.put(ActionContext.LOCALE, locale);//extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));extraContext.put(StrutsStatics.HTTP_REQUEST, request);extraContext.put(StrutsStatics.HTTP_RESPONSE, response);extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);// helpers to get access to request/session/application scopeextraContext.put("request", requestMap);extraContext.put("session", sessionMap);extraContext.put("application", applicationMap);extraContext.put("parameters", parameterMap);AttributeMap attrMap = new AttributeMap(extraContext);extraContext.put("attr", attrMap);return extraContext;}

?

(2)ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
??????????????????? namespace, name, extraContext, true, false);默認由DefaultActionProxyFactory類創建ActionProxy 。

Java代碼 public ActionProxy createActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {//創建ActionProxyActionProxy proxy = new DefaultActionProxy(namespace, actionName, extraContext, executeResult, cleanupContext);container.inject(proxy);//為了創建ActionInvocationproxy.prepare();return proxy;}

?

? ? proxy.prepare(); 在這方法中創建ActionInvocation(默認為DefaultActionInvocation),主要由ActionInvocation來調度Action 的實際操作

Java代碼 public void prepare() throws Exception {String profileKey = "create DefaultActionProxy: ";try {UtilTimerStack.push(profileKey);config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);if (config == null && unknownHandler != null) {config = unknownHandler.handleUnknownAction(namespace, actionName);}if (config == null) {String message;if ((namespace != null) && (namespace.trim().length() > 0)) {message = LocalizedTextUtil.findDefaultText(XWorkMessages.MISSING_PACKAGE_ACTION_EXCEPTION, Locale.getDefault(), new String[]{namespace, actionName});} else {message = LocalizedTextUtil.findDefaultText(XWorkMessages.MISSING_ACTION_EXCEPTION, Locale.getDefault(), new String[]{actionName});}throw new ConfigurationException(message);}invocation = new DefaultActionInvocation(objectFactory, unknownHandler, this, extraContext, true, actionEventListener);//如果method 為空,則this.method = "execute";resolveMethod();} finally {UtilTimerStack.pop(profileKey);}}

?

? ?在創建ActionInvocation 的時候有個主要的方法 init();

Java代碼 protected DefaultActionInvocation(final ObjectFactory objectFactory, final UnknownHandler handler, final ActionProxy proxy, final Map extraContext, final boolean pushAction, final ActionEventListener actionEventListener) throws Exception {UtilTimerStack.profile("create DefaultActionInvocation: ", new UtilTimerStack.ProfilingBlock<Object>() {public Object doProfiling() throws Exception {DefaultActionInvocation.this.proxy = proxy;DefaultActionInvocation.this.objectFactory = objectFactory;DefaultActionInvocation.this.extraContext = extraContext;DefaultActionInvocation.this.pushAction = pushAction;DefaultActionInvocation.this.unknownHandler = handler;DefaultActionInvocation.this.actionEventListener = actionEventListener;init();//這里return null;}});}

??

? ?init();方法,該方法創建了Action 和ActionContext

Java代碼 private void init() throws Exception {Map contextMap = createContextMap();//創建ActioncreateAction(contextMap);if (pushAction) {//把Action 放進值棧stack.push(action);}//創建ActionContextinvocationContext = new ActionContext(contextMap);invocationContext.setName(proxy.getActionName());// get a new List so we don't get problems with the iterator if someone changes the listList interceptorList = new ArrayList(proxy.getConfig().getInterceptors());interceptors = interceptorList.iterator();}

???

??? 創建Action,通過objectFactory 進行創建,而這個類在struts.properties中可以重寫這個屬性 。默認為SpringObjectFactory:struts.objectFactory=spring,在前面BeanSelectionProvider中通過配置文件為ObjectFactory設置實現類??

Java代碼 protected void createAction(Map contextMap) {// load actionString timerKey = "actionCreate: "+proxy.getActionName();try {UtilTimerStack.push(timerKey);action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);} catch (InstantiationException e) {throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());} catch (IllegalAccessException e) {throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());} catch (Exception e) {String gripe = "";if (proxy == null) {gripe = "Whoa! No ActionProxy instance found in current ActionInvocation. This is bad ... very bad";} else if (proxy.getConfig() == null) {gripe = "Sheesh. Where'd that ActionProxy get to? I can't find it in the current ActionInvocation!?";} else if (proxy.getConfig().getClassName() == null) {gripe = "No Action defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";} else {gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ", defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";}gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");throw new XWorkException(gripe, e, proxy.getConfig());} finally {UtilTimerStack.pop(timerKey);}if (actionEventListener != null) {action = actionEventListener.prepare(action, stack);}}public Object buildAction(String actionName, String namespace, ActionConfig config, Map extraContext) throws Exception {return buildBean(config.getClassName(), extraContext);}public Object buildBean(String className, Map extraContext) throws Exception {return buildBean(className, extraContext, true);}public Object buildBean(String className, Map extraContext, boolean injectInternal) throws Exception {Class clazz = getClassInstance(className);Object obj = buildBean(clazz, extraContext);if (injectInternal) {injectInternalBeans(obj);}return obj;} Java代碼 ?protected Object injectInternalBeans(Object obj) {if (obj != null && container != null) {container.inject(obj);}return obj;}

??

??? proxy.execute();方法是struts2 中流程的重要方法。

?

Java代碼 public String execute() throws Exception {ActionContext nestedContext = ActionContext.getContext();ActionContext.setContext(invocation.getInvocationContext());String retCode = null;String profileKey = "execute: ";try {UtilTimerStack.push(profileKey);//這個是重點,主要的攔截器功能在這實現,執行返回跳轉的字符串retCode = invocation.invoke();} finally {if (cleanupContext) {ActionContext.setContext(nestedContext);}UtilTimerStack.pop(profileKey);}return retCode;}

??

? ?invoke 方法調用了DefaultActionInvocation的invoke()去實現Action的調用

Java代碼 public String invoke() throws Exception {......try {......if (interceptors.hasNext()) {// (1)final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();UtilTimerStack.profile("interceptor: "+interceptor.getName(), new UtilTimerStack.ProfilingBlock<String>() {public String doProfiling() throws Exception {resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);return null;}});} else {resultCode = invokeActionOnly();}if (!executed) {// (2)if (preResultListeners != null) {// (2)-1for (Iterator iterator = preResultListeners.iterator();iterator.hasNext();) {PreResultListener listener = (PreResultListener) iterator.next();String _profileKey="preResultListener: ";try {UtilTimerStack.push(_profileKey);listener.beforeResult(this, resultCode);}finally {UtilTimerStack.pop(_profileKey);}}}if (proxy.getExecuteResult()) {// (2)-2executeResult();}executed = true;}return resultCode;}finally {UtilTimerStack.pop(profileKey);}}

?

??? 整個方法主要由2個if從句分割,在(1)處的if從句中,主要實現了攔截器的"遞歸"調用,說它是遞歸調用,其實是一種非傳統的遞歸。傳統的遞歸應該是函數調用自身,最后達成一定條件后退出,但是這里是將自身的引用作為參數傳遞給intercept(),然后在intercept()內部再調用DefaultActionInvocation的invoke(),實現了遞歸調用。

利用這種方式,實現了攔截器和Action的如下的調用邏輯:

Interceptor1
Interceptor2
Interceptor3
Action
Interceptor3
Interceptor2
Interceptor1

??? 最后,當interceptors.hasNext()返回false時,也就是全部攔截器調用完畢之后,函數調用了invokeActionOnly();去實現Action的調用:

Java代碼 public String invokeActionOnly() throws Exception {return invokeAction(getAction(), proxy.getConfig());}

?

?? invokeActionOnly()內部是使用invokeAction()去實現Action的調用的,源代碼如下:

Java代碼 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {String methodName = proxy.getMethod();if (LOG.isDebugEnabled()) {LOG.debug("Executing action method = " + actionConfig.getMethodName());}String timerKey = "invokeAction: "+proxy.getActionName();try {UtilTimerStack.push(timerKey);Method method;try {method = getAction().getClass().getMethod(methodName, new Class[0]);} catch (NoSuchMethodException e) {try {String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);method = getAction().getClass().getMethod(altMethodName, new Class[0]);} catch (NoSuchMethodException e1) {throw e;}}Object methodResult = method.invoke(action, new Object[0]);if (methodResult instanceof Result) {this.result = (Result) methodResult;return null;} else {return (String) methodResult;}} catch (NoSuchMethodException e) {throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");} catch (InvocationTargetException e) {Throwable t = e.getTargetException();if (actionEventListener != null) {String result = actionEventListener.handleException(t, getStack());if (result != null) {return result;}}if (t instanceof Exception) {throw(Exception) t;} else {throw e;}} finally {UtilTimerStack.pop(timerKey);}}

?

??? 由這句Object methodResult = method.invoke(action, new Object[0]);可以看出,最后通過反射實現了Action的執行方法的調用。


??? 調用完方法之后,invoke()方法的流程來到了(2)處,由于剛剛調用完Action的那次invoke()調用此時executed為false,所以可以進入此處的if語句。
(2)-1處調用了在PreResultListener中的定義的一些執行Result前的操作。
(2)-2處則根據配置文件中的設置執行Result。

Java代碼 private void executeResult() throws Exception {result = createResult();// 根據配置文件構建ResultString timerKey = "executeResult: "+getResultCode();try {UtilTimerStack.push(timerKey);if (result != null) {result.execute(this);} else if (resultCode != null && !Action.NONE.equals(resultCode)) {throw new ConfigurationException("No result defined for action " + getAction().getClass().getName() + " and result " + getResultCode(), proxy.getConfig());} else {if (LOG.isDebugEnabled()) {LOG.debug("No result returned for action "+getAction().getClass().getName()+" at "+proxy.getConfig().getLocation());}}} finally {UtilTimerStack.pop(timerKey);}}

?

于是,最終的調用順序應該是:
Interceptor1
Interceptor2
Interceptor3
Action
PreResultListener
Result
Interceptor3
Interceptor2
Interceptor1

?

總結

以上是生活随笔為你收集整理的struts2 处理请求流程分析(结合源码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

涩五月婷婷| 久久久久久久久久国产精品 | 香蕉蜜桃视频 | 五月婷婷中文网 | 六月丁香六月婷婷 | 91亚洲国产成人久久精品网站 | 久久久久在线观看 | 黄色福利网站 | 精品国产1区2区3区 国产欧美精品在线观看 | 久久中文字幕视频 | 国产区高清在线 | 欧美一二三区播放 | 国产日产av | 国产精品免费在线播放 | 色就色,综合激情 | 国产999精品久久久久久绿帽 | 国产一区视频在线观看免费 | 久久精品欧美日韩精品 | 天天射综合 | 中文字幕一区二区三区四区久久 | 992tv在线成人免费观看 | 国产高清在线a视频大全 | 成人精品一区二区三区中文字幕 | 亚洲视频专区在线 | 欧美在线观看小视频 | 亚洲精品国产日韩 | 九九久久免费视频 | 日韩电影在线观看中文字幕 | 国产69精品久久99不卡的观看体验 | 天堂va在线高清一区 | 日本久久久精品视频 | 国产一区在线免费观看视频 | 六月激情久久 | 五月天综合激情网 | www.黄色片网站 | 久草精品在线观看 | 久久综合亚洲鲁鲁五月久久 | 综合成人在线 | 欧美久久久一区二区三区 | 欧美日韩p片 | 日批网站免费观看 | 免费久久99精品国产 | 毛片随便看| 午夜精品久久久久久久久久久 | 在线视频观看国产 | 午夜av影院 | 久久精品79国产精品 | 热久久精品在线 | 久久在线视频在线 | 超碰国产97| 日韩高清一区二区 | 综合激情网 | 色多多视频在线 | 国产日韩亚洲 | 91免费观看国产 | 91精品国自产在线观看欧美 | 亚洲一级黄色大片 | 免费激情网 | 中文字幕在线观看第二页 | 不卡精品| 国产一级二级在线观看 | 久久超| 国产一区二区三精品久久久无广告 | 日韩欧美视频一区 | 久久99影院| 岛国av在线不卡 | 国内久久久久久 | 在线观看你懂的网址 | 国产理论在线 | www.午夜色.com | 色婷婷视频在线观看 | 午夜在线观看 | 91亚洲在线观看 | 九色91在线视频 | 五月婷婷一区二区三区 | 日韩精品久久久久久 | 亚洲美女在线国产 | 久久成人国产精品一区二区 | 中文字幕免费高 | 免费视频97 | 欧美成人tv | 18国产精品白浆在线观看免费 | 免费日韩一区二区三区 | www国产亚洲精品久久麻豆 | 国产精品高清一区二区三区 | 中文字幕一区二区三区四区在线视频 | 国产色视频 | 国产精品一区二区三区在线播放 | 中文字幕在线观看资源 | 国产91精品在线播放 | 国产精品一区二区在线看 | 久久看看 | 免费男女羞羞的视频网站中文字幕 | 999视频精品 | 久久官网 | 99福利片 | 欧美日韩精品免费观看视频 | 免费日韩在线 | 中文视频一区二区 | 亚洲男人天堂2018 | 婷婷播播网 | 在线国产不卡 | 亚洲成色 | 午夜狠狠操 | 亚洲免费成人av电影 | 国产精品综合久久久久久 | 久久免费观看少妇a级毛片 久久久久成人免费 | 久久久亚洲精华液 | 日韩一区二区三区在线观看 | 伊人久久精品久久亚洲一区 | 亚洲午夜av久久乱码 | 亚洲精选在线 | 国产精品伦一区二区三区视频 | av成人动漫在线观看 | 欧美看片| 欧美精品一区二区免费 | 日本美女xx | 在线观看黄色国产 | 6080yy午夜一二三区久久 | 在线观看视频在线观看 | 国产精品99久久久久久久久 | 久久久99精品免费观看乱色 | 免费视频久久久 | 五月天婷婷在线视频 | 少妇搡bbb| 国产亚洲久一区二区 | av一区在线播放 | 欧美日韩免费视频 | 91人人澡人人爽 | 午夜影院日本 | 国产成人精品亚洲精品 | 天天综合久久 | 在线观看播放av | 久久久人 | 97人人精品| 日本性xxxxx 亚洲精品午夜久久久 | 一区二区三区在线观看免费视频 | 丁香九月激情综合 | www.午夜| 精品亚洲免费视频 | 免费观看视频的网站 | 国产精品久久影院 | 97碰碰精品嫩模在线播放 | 国产亚洲成av片在线观看 | 日本激情视频中文字幕 | 免费在线观看av网址 | 91xav| 欧美极品在线播放 | 在线免费日韩 | 狠狠做深爱婷婷综合一区 | 波多野结衣在线观看视频 | 永久免费精品视频 | 日韩在线视频不卡 | 色综合久久久 | 久久久久国 | 亚洲最快最全在线视频 | 久久草草热国产精品直播 | 天天色天天骑天天射 | 国产黄色一级片 | 高清av影院| 中文字幕视频 | 91精品国产九九九久久久亚洲 | 精品久久久久国产 | 亚洲成人高清在线 | 六月激情丁香 | 美女久久久久久久 | 国产另类av | 99精品观看 | 欧美日韩免费一区二区 | 婷婷六月天天 | 午夜国产一区二区 | 欧美国产精品久久久久久免费 | 又黄又爽免费视频 | 中文字幕免费高 | 五月婷久 | av在线永久免费观看 | av免费看在线| 国产综合片 | 成人久久久久 | 国产一区二区三区午夜 | 久久狠狠婷婷 | 色婷婷福利视频 | 久久人人爽人人爽人人 | 久草在线视频首页 | 一区二区视频在线观看免费 | 98久久 | 狠狠干狠狠艹 | 亚洲国产精品va在线看 | 伊人天天色 | 99麻豆久久久国产精品免费 | 夜夜躁狠狠躁日日躁 | 国产精品久久久久久久久岛 | 69久久夜色精品国产69 | 国产精品自拍av | 国产精品美女久久久久aⅴ 干干夜夜 | 欧美精品久久久久a | 69亚洲精品 | 日韩av在线小说 | 欧美 日韩 性 | 欧美成人a在线 | 久久久91精品国产一区二区精品 | 国产精品亚洲成人 | 国产乱码精品一区二区三区介绍 | 色a网| 国产99爱 | 日本精品在线视频 | 国产中文视频 | www.xxx.性狂虐 | 婷婷视频 | 四虎在线视频 | 色婷婷综合久久久久 | 久久电影国产免费久久电影 | 国产一级不卡视频 | 久久超级碰| 国产精品毛片一区二区 | 国产九九精品视频 | 在线免费黄色毛片 | 天天操天天色天天 | 日韩精品首页 | 久久亚洲区 | 干干干操操操 | 99热在线看 | 毛片久久久| 丁香激情五月婷婷 | 亚洲视屏 | 福利视频导航网址 | 福利视频一区二区 | 在线免费观看视频一区二区三区 | 狠狠干狠狠艹 | 国产中文字幕第一页 | 一区二区视频在线播放 | 日韩视频二区 | 免费日韩在线 | 日本视频精品 | 色国产视频| 国产高清网站 | 亚洲欧美日韩在线看 | 欧美最爽乱淫视频播放 | 日批视频在线 | 人九九精品 | 婷婷去俺也去六月色 | 在线观看亚洲免费视频 | 久久综合色天天久久综合图片 | 91av视频播放 | www国产亚洲 | av天天干| 中文字幕一区av | 欧美污网站 | 毛片精品免费在线观看 | 麻花豆传媒一二三产区 | 中文亚洲欧美日韩 | 丁香婷婷基地 | 插综合网 | 美女黄频视频大全 | 在线观看中文字幕亚洲 | 黄色成人av在线 | 精品国产免费av | 99久久久久国产精品免费 | а天堂中文最新一区二区三区 | 成人av手机在线 | 蜜臀91丨九色丨蝌蚪老版 | 91av短视频 | 久久精品欧美 | 午夜精品久久久久99热app | 亚洲高清国产视频 | 久久黄色片 | www.av中文字幕.com | 国内亚洲精品 | 国产精品99蜜臀久久不卡二区 | 在线观看亚洲精品 | 激情av五月婷婷 | 91成人免费在线视频 | 久久久久久网址 | 日韩av电影手机在线观看 | 99这里都是精品 | 天天狠狠干 | 亚洲欧美一区二区三区孕妇写真 | 久久国产精品99久久久久久老狼 | 97精品国自产拍在线观看 | 亚洲经典视频在线观看 | 国产精品免费成人 | 天天综合网 天天 | 国产日本三级 | 91av色 | 国产麻豆精品95视频 | 国产不卡在线观看 | 日韩欧美一区二区在线观看 | 国产a高清 | 91综合视频在线观看 | 久久国产精品99久久人人澡 | www.狠狠插.com | 二区视频在线观看 | 国产一二三四在线视频 | 天天爽夜夜爽精品视频婷婷 | 国产精品一区二区久久久久 | 成年一级片 | 日韩二区在线 | 色5月婷婷| 久草99 | 亚洲国产97在线精品一区 | 色吧久久 | 国产精品久久久av久久久 | 久久国产精品99久久久久久丝袜 | 久久久久久综合网天天 | 久久综合天天 | 2019中文字幕网站 | 欧美日韩精品在线免费观看 | 成片人卡1卡2卡3手机免费看 | 国产精品国产三级国产不产一地 | 激情久久一区二区三区 | 亚洲一区二区观看 | 亚洲自拍偷拍色图 | 久久99这里只有精品 | 久久精品99精品国产香蕉 | 在线观看免费av网站 | 久久精品日本啪啪涩涩 | 成人a在线观看 | 婷婷丁香激情综合 | 国产精品美女久久久久aⅴ 干干夜夜 | 久久久久人人 | 国产91综合一区在线观看 | 精品国产伦一区二区三区观看体验 | 国产精品久久久久久久久久了 | 黄色网中文字幕 | 国产一区 在线播放 | 亚洲一区二区三区毛片 | 成人久久久久久久久 | 97超碰中文字幕 | 日日夜夜狠狠干 | 久久高清国产视频 | 深爱激情五月网 | 久久久亚洲精华液 | 婷婷av电影 | 麻豆超碰 | 国产黄色电影 | 午夜精品视频一区二区三区在线看 | 亚洲精品播放 | 日本在线免费看 | 手机在线中文字幕 | 国产激情小视频在线观看 | 九九精品毛片 | 四虎国产精 | 欧美一区二区三区四区夜夜大片 | 久久精品一二三 | 亚洲自拍偷拍色图 | 日韩91av| 婷婷性综合 | 中文字幕超清在线免费 | 国产精品一区电影 | 中文字幕久久网 | 国产精品1区2区3区 久久免费视频7 | 日韩精品黄 | 欧美精品一区在线 | 国产精品一区二区av | 九九热av | 日韩一区二区三区免费视频 | 超碰人人99 | av免费观看高清 | 国产高清视频在线播放 | 午夜精品久久久久久久久久久久 | 午夜精品av | 国产一区二区三区久久久 | 国产97在线观看 | 色婷婷骚婷婷 | 叶爱av在线 | 97在线观视频免费观看 | 欧美大片aaa | 国产在线看一区 | 色狠狠操 | 人人草在线视频 | 狠狠的干狠狠的操 | 1024手机在线看 | 日韩av中文字幕在线免费观看 | 天天看天天操 | 婷婷社区五月天 | 亚洲一区二区视频在线播放 | 美女视频a美女大全免费下载蜜臀 | 午夜影视一区 | 久久天天躁夜夜躁狠狠躁2022 | 三级黄色免费片 | 亚洲美女视频在线 | 日日夜夜网 | 日韩一区二区在线免费观看 | 国产麻豆果冻传媒在线观看 | 美女久久精品 | 五月天婷婷免费视频 | 毛片网站在线观看 | 亚洲激情视频在线 | 欧美一区二区精品在线 | 五月婷婷六月丁香 | 伊人中文字幕在线 | 日本少妇视频 | 免费看三片 | 日韩精品久久久久久 | 日日干av | 狠狠成人 | 国产午夜精品福利视频 | 久久久久久国产精品免费 | 五月天中文字幕 | 国产亚洲综合性久久久影院 | 久久久www成人免费毛片 | 日韩1级片 | 国产精品久久伊人 | 婷婷五月在线视频 | 亚洲 在线 | 人人草网站| 国产免费av一区二区三区 | 免费视频久久久久 | 中文字幕婷婷 | 在线日韩一区 | 日韩视频一区二区三区 | av在线播放网址 | 国产成人精品国内自产拍免费看 | 日本精品一区二区三区在线播放视频 | 亚洲精品免费播放 | 婷久久 | 成人国产精品一区 | 中文字幕中文中文字幕 | 免费中午字幕无吗 | 欧美日韩精品区 | 99久久er热在这里只有精品15 | 欧美成人按摩 | 亚洲v欧美v国产v在线观看 | 黄色app网站在线观看 | 啪啪免费视频网站 | 色老板在线 | 久久久91精品国产一区二区精品 | 成人免费视频视频在线观看 免费 | 国产 在线 高清 精品 | av动图| 亚洲va欧美| 狠狠色丁香婷婷综合视频 | 国产精品久久精品 | 国产精品理论片在线观看 | 97看片 | 日本性生活一级片 | 99热超碰| 色狠狠狠 | 亚洲成人黄色在线观看 | 久久成年人视频 | 欧美成年人在线视频 | 99热国产在线| 亚州黄色一级 | 天天射天天舔天天干 | 色在线网 | 一级黄色片毛片 | 蜜桃视频在线观看一区 | 午夜精品福利在线 | 婷婷深爱激情 | 三上悠亚在线免费 | 精品国产99国产精品 | 成人av高清 | 日日摸日日添夜夜爽97 | 一区二区三区免费 | 天天综合五月天 | 色多多视频在线观看 | 国产精品久久久久影院日本 | 人人爽人人澡人人添人人人人 | 91超级碰碰 | 免费观看久久久 | 97色在线观看| 欧亚久久 | 亚洲成av人影片在线观看 | 很黄很黄的网站免费的 | 99精品视频免费看 | 成人在线免费视频 | 91视频 - v11av| 成年人在线视频观看 | 97视频在线观看视频免费视频 | 操操操人人人 | 一级α片免费看 | 国产经典av | 婷婷久久丁香 | 日韩高清无线码2023 | 国产美女网站视频 | 国产高清免费在线观看 | 国内精品久久久久久中文字幕 | 精品国精品自拍自在线 | 精品国产一二三 | 日韩和的一区二在线 | 久久 在线 | 午夜av电影 | 色偷偷88888欧美精品久久久 | 亚洲精品视频免费观看 | 成人小视频在线观看免费 | 天天曰夜夜操 | 顶级bbw搡bbbb搡bbbb | 国产高清免费在线观看 | 天堂av在线7 | 97视频在线观看播放 | 色网站在线 | 久久国产网 | 成人久久久精品国产乱码一区二区 | 日韩av网页 | 成年人黄色免费网站 | 国产精品久久久久久久久久 | 久久久久久看片 | 成人影视免费 | 久久电影中文字幕视频 | 国产香蕉久久精品综合网 | 久草在线视频精品 | 福利一区在线视频 | 在线成人免费电影 | 狠狠色丁香婷婷综合久小说久 | 午夜精品久久久久久久99无限制 | 国产老太婆免费交性大片 | 香蕉在线视频播放网站 | 日韩在线观看视频一区二区三区 | 欧美一级视频免费 | 九色91在线视频 | 五月婷婷久草 | 精品成人a区在线观看 | 中文字幕在线免费观看视频 | 岛国av在线| 成人av在线直播 | 国产精品中文字幕在线播放 | 又色又爽又黄高潮的免费视频 | 欧美动漫一区二区三区 | 一区二区高清在线 | 99在线看| 国产精品久久久久久久久久久久午夜 | 日韩高清在线一区二区三区 | 色www精品视频在线观看 | 色七七亚洲影院 | 一区二区三区四区不卡 | 天天舔天天搞 | 欧美日韩在线视频观看 | 精品国产一区二 | 精品亚洲免a | 国产视频不卡 | 国产精品网红福利 | 国产视频一区二区三区在线 | 久久天天躁夜夜躁狠狠躁2022 | 国产韩国精品一区二区三区 | 久久综合色影院 | 日日夜夜精品免费观看 | 99国产高清| 亚洲欧美精品在线 | 美女在线观看av | 91干干干| 97在线视频免费播放 | 91爱爱网址 | 九九热免费精品视频 | 四虎最新域名 | 在线中文字母电影观看 | 午夜三级在线 | 久草网视频在线观看 | 久操久| 国产精品欧美激情在线观看 | 久久久黄视频 | 久久久精品国产一区二区三区 | 中文字幕在线网 | 色噜噜日韩精品一区二区三区视频 | 国产精品3区 | 国产福利91精品 | 日韩二区在线 | 色视频网页 | 亚洲精品1234区 | va视频在线| 91免费试看 | 亚洲国产网站 | av免费网站观看 | 久久久久久久久久久久电影 | 日韩高清成人 | 一级做a爱片性色毛片www | 国产精品一区二区视频 | 成人免费一区二区三区在线观看 | 在线黄网站 | 日本中文字幕系列 | 久久久久久久国产精品影院 | 日本3级在线观看 | 91av短视频 | 国产91精品在线播放 | 国产一区二区三区四区在线 | 99久免费精品视频在线观看 | 美女黄频在线观看 | 最新av在线播放 | 日韩精品亚洲专区在线观看 | 992tv成人免费看片 | 免费观看午夜视频 | 在线黄网站 | 国产黄色在线 | 青草草在线视频 | 不卡av电影在线观看 | 亚洲成人网在线 | 亚洲天堂香蕉 | 香蕉视频亚洲 | av电影免费观看 | 在线欧美小视频 | 天天色 天天| 亚洲综合国产精品 | 99中文在线| 91香蕉国产 | 亚洲天堂在线观看完整版 | 国产精品免费观看网站 | 黄色视屏在线免费观看 | 91丨porny丨九色 | 日韩av一区二区在线播放 | www国产精品com | 91福利视频在线 | 国产中文字幕视频在线 | 日韩欧美国产免费播放 | 亚洲精品在线一区二区三区 | 日韩精品一区二 | 天天精品视频 | 天天插天天 | 99热在线免费观看 | 久久久高清免费视频 | 黄色日本免费 | 国产小视频在线免费观看 | 99在线播放| 欧美日韩精品在线一区二区 | 婷婷丁香激情五月 | 17婷婷久久www | 国产高清不卡 | 色婷婷午夜 | 久久99这里只有精品 | 黄色小视频在线观看免费 | 日韩| 亚洲电影久久久 | 99久久精品免费 | 麻豆视频观看 | 天天操天天干天天综合网 | 综合色天天 | 国产成人精品国内自产拍免费看 | 国产123区在线观看 国产精品麻豆91 | 激情久久久久久久久久久久久久久久 | 蜜桃av久久久亚洲精品 | 久草免费看 | 日韩高清免费在线观看 | 国偷自产中文字幕亚洲手机在线 | 久久国产网站 | 91中文字幕在线视频 | 日韩在线观看免费 | 久久久久久久久久久久电影 | 国产视频2021 | av电影一区 | 欧美91av | 成人免费在线视频观看 | 美女黄频网站 | 天天艹天天操 | 最近的中文字幕大全免费版 | 久久伊人操 | 99re8这里有精品热视频免费 | 日韩免费在线看 | 成人啪啪18免费游戏链接 | 午夜国产在线观看 | 免费婷婷 | 成人在线免费看 | 97视频免费在线 | 一级a性色生活片久久毛片波多野 | 亚洲aⅴ久久精品 | 精品国产伦一区二区三区观看体验 | 激情五月婷婷综合 | 91片黄在线观看动漫 | av资源网在线播放 | 中文字幕中文中文字幕 | 色播99| 久久久久久久久久久免费视频 | 欧美a性 | 天天操比 | 久久久不卡影院 | 成人黄色免费在线观看 | 亚洲成人国产精品 | 色av资源网 | 天天射,天天干 | 91大神精品视频在线观看 | 日韩欧美高清一区二区 | 国产成人精品久久亚洲高清不卡 | 久久久久一区 | 久久久国产电影 | 亚洲精品婷婷 | www.夜夜操.com | 成人动图 | 国产1区在线观看 | 伊人久久在线观看 | 蜜臀精品久久久久久蜜臀 | 天天视频亚洲 | 中文字幕中文字幕在线中文字幕三区 | 黄色www | 国产精品一区二区在线观看 | 91大片网站 | 天天·日日日干 | 天天干天天操 | 亚洲精品白浆高清久久久久久 | 一区二区三区四区免费视频 | 国产精品都在这里 | 一区二区三区在线免费播放 | 久久国产精品一区二区三区四区 | 日韩中文字幕在线观看 | 欧美精品久久久久久久久久久 | 91精选 | 手机在线看片日韩 | 亚洲国产影院av久久久久 | 丁香花中文在线免费观看 | 亚洲午夜av | 97超碰资源网 | 国产日韩在线一区 | 一级欧美一级日韩 | 久久午夜国产 | 三级黄色大片在线观看 | 黄色一区二区在线观看 | 欧美婷婷综合 | 色婷婷电影网 | 色欲综合视频天天天 | 天天插天天干 | 日韩av影片在线观看 | 亚洲一级国产 | 国产高清不卡在线 | 国产精品久久久久久久久费观看 | 在线国产福利 | 日韩婷婷| 成人免费在线观看电影 | 美女黄频网站 | 99久久婷婷国产综合亚洲 | 国产精品久久久久久一二三四五 | 亚洲专区欧美 | 亚洲综合欧美精品电影 | 毛片网站观看 | 国产美女视频网站 | 日韩爱爱片 | 欧美性极品xxxx做受 | 国产精品自产拍 | 国产成人av | 91在线看黄| 欧美精品久久人人躁人人爽 | 亚洲成人网av | 西西444www| 日韩午夜在线观看 | 国产精品一区二区在线观看 | 日韩精品免费在线播放 | 成人久久毛片 | 国产精品一区二区你懂的 | 在线只有精品 | 在线观看视频国产一区 | 欧美日韩精品在线播放 | 国产精品女人网站 | 久久免费视频这里只有精品 | 娇妻呻吟一区二区三区 | 中文字幕中文中文字幕 | av在线看片| 成人av片在线观看 | 六月婷婷久香在线视频 | 521色香蕉网站在线观看 | 麻豆一区二区三区视频 | 一区二区三区免费网站 | 免费在线一区二区三区 | 又湿又紧又大又爽a视频国产 | 日韩欧美精品在线观看视频 | 欧美在线aa | 国产在线观看午夜 | 国产黄影院色大全免费 | 久久免费试看 | 国产精品va在线观看入 | 三级黄色大片在线观看 | 在线观看亚洲精品 | 91麻豆国产 | 人人操日日干 | 超碰日韩在线 | 成人精品在线 | 天天摸天天操天天爽 | 国产高清av免费在线观看 | 999久久国精品免费观看网站 | 日韩av网站在线播放 | 成年人电影毛片 | 一区二区视频在线免费观看 | 免费在线观看一级片 | 国产精品热 | 91网页版在线观看 | 免费观看一级视频 | 韩国三级av在线 | 亚洲成av人影片在线观看 | 玖玖在线看 | 久久黄色片子 | 亚洲欧美视频在线播放 | 91中文字幕永久在线 | 视频在线观看91 | 国产美腿白丝袜足在线av | 久久久久成人精品免费播放动漫 | 在线观看中文字幕第一页 | 久久久午夜精品理论片中文字幕 | 国产一区二区电影在线观看 | 97精品国产| 五月婷婷一区二区三区 | 伊人超碰在线 | 久久久受www免费人成 | 免费成人av在线看 | av先锋中文字幕 | 亚洲在线| 国产精久久久久久久 | 午夜精品一区二区三区免费视频 | 91成品人影院 | 欧美日韩三级在线观看 | 欧美成人手机版 | 久久色中文字幕 | 亚洲aⅴ免费在线观看 | 4hu视频 | 国产精品久久久网站 | 深爱激情站 | 亚洲精品www久久久 www国产精品com | 欧美精品一区二区在线观看 | 在线天堂视频 | 国产在线播放观看 | 亚洲伊人成综合网 | 91九色视频国产 | 在线91视频 | 国产精品系列在线 | 97**国产露脸精品国产 | 成人三级视频 | 日韩av网页 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 精品国产网址 | 91片黄在线观看动漫 | 日韩电影在线观看中文字幕 | 日韩最新理论电影 | 国产在线观看中文字幕 | 成人久久久精品国产乱码一区二区 | 涩涩伊人| 少妇精品久久久一区二区免费 | 精品理论片 | 国产精品一区二区三区久久久 | 日一日干一干 | 日韩一级电影在线观看 | 国产丝袜一区二区三区 | 欧美 亚洲 另类 激情 另类 | 日日草视频 | 欧美日韩在线第一页 | 伊人伊成久久人综合网小说 | 黄网站色成年免费观看 | 国产精品久久久久久久久久久久午夜片 | 免费日韩 精品中文字幕视频在线 | 国产精品国产精品 | 成年免费在线视频 | 国产精品第 | 丁香六月av | 在线观看亚洲视频 | 亚洲黄a | 黄在线免费看 | 欧美日韩国产一区 | 人人添人人澡人人澡人人人爽 | 国产精品久久久久一区 | 日韩av免费在线电影 | 在线天堂日本 | 狠狠gao | 国产午夜精品视频 | 国产伦精品一区二区三区四区视频 | 五月在线 | 97国产在线播放 | 青春草免费在线视频 | 91网址在线观看 | 天天操天天干天天插 | 欧美日韩在线看 | 成人日批视频 | 日本性生活一级片 | 国语黄色片 | 狠狠色伊人亚洲综合成人 | 国产99久久久国产精品成人免费 | 欧美日韩性视频在线 | 日韩欧美在线免费观看 | 国产精品国产亚洲精品看不卡 | 成人在线视频观看 | 人人爽人人干 | 国产视频午夜 | 国产免费观看高清完整版 | 狠狠干夜夜操 | 射射射av| 色99视频| 免费观看黄色av | 超碰av在线 | 欧洲在线免费视频 | 麻豆国产精品va在线观看不卡 | 又黄又刺激视频 | 在线视频 日韩 | 99成人精品 | 又黄又爽的免费高潮视频 | 操操操人人 | 手机成人免费视频 | 免费av网站观看 | 91人网站 | 日韩性xxxx | 国内精品视频久久 | 黄色在线网站噜噜噜 | 天堂av一区二区 | 亚洲人成人在线 | 中文字幕久久久精品 | 一本一本久久a久久精品牛牛影视 | 成人免费观看网站 | 欧美国产一区在线 | 欧美一级xxxx | 久久免费视频5 | 中文免费在线观看 | 国产香蕉97碰碰碰视频在线观看 | 亚洲精品在线观看网站 | 综合色中文 | 911久久香蕉国产线看观看 | 久久精品视频观看 | 国产精品成人一区二区 | 2020天天干夜夜爽 | 色婷婷狠| 亚洲天天在线日亚洲洲精 | 成人免费看电影 | 日韩欧美在线不卡 | 日韩电影在线观看中文字幕 | 亚洲伦理精品 | 日韩区欧美久久久无人区 | 日韩精品免费在线观看 | 国产99久久久国产精品 | 亚洲亚洲精品在线观看 | 免费大片av | 久久伦理电影 | 在线日韩视频 | 国产精品理论片在线观看 | 国产视频18 | 亚洲精品视频网站在线观看 | 人人爽人人舔 | 九色91福利 | 日本精品二区 | 俺要去色综合狠狠 | 草久在线视频 | 久久激情综合网 | 久久成人国产精品入口 | 久久久亚洲国产精品麻豆综合天堂 | 亚洲在线观看av | 国内视频在线 | 亚洲午夜久久久久久久久久久 | 日日干日日色 | 久久免费观看少妇a级毛片 久久久久成人免费 | 91高清不卡 | 久久久黄视频 | 久久99精品热在线观看 | 国产精品短视频 | av在线精品 | www.色五月.com | 国产美女无遮挡永久免费 | 亚洲精品视频在线免费播放 | 日韩精品免费在线 | 国产亚洲精品中文字幕 | 手机av资源 | 极品久久久 | 亚洲成人黄色在线观看 | 国产69精品久久久久9999apgf | 波多野结衣在线中文字幕 | 一区二区三区视频 | 国产精品尤物视频 | 免费在线观看视频a | 69久久久久久久 | 99久久电影| 18+视频网站链接 | 成人亚洲精品国产www | 国产精品理论片在线观看 | 日韩精品久久久久久 | 香蕉精品视频在线观看 | 香蕉视频网站在线观看 | 国产精品久久免费看 | 国产精品ⅴa有声小说 | 久久看免费视频 | 亚洲影视九九影院在线观看 | 国产精品久久久久婷婷 | 久草在线一免费新视频 | 久久精品99精品国产香蕉 | 福利视频网址 | 免费在线观看av网站 | 国产黄色精品 | 国产精品破处视频 | 日韩欧美电影 | 丁香伊人网 | 视频在线观看99 | 亚洲精品在线资源 | 在线日韩中文字幕 | 国产亚洲情侣一区二区无 | 免费看一级黄色大全 | 日韩大片在线看 | 亚洲片在线资源 | 日韩欧美69 | 看国产黄色片 | 亚洲免费观看在线视频 | 爱射综合| 99热精品久久 | 99精彩视频| 99在线视频网站 | 在线精品视频在线观看高清 | 麻豆免费在线播放 | 91亚洲精品久久久久图片蜜桃 | 六月婷操 | 99视频| 日韩精品视频第一页 | 国产精品视频永久免费播放 | 美女视频国产 | 日韩区欠美精品av视频 | 国产精品视频线看 | 特级西西人体444是什么意思 | 久久国产一二区 | 国产成人福利在线观看 | 精品在线播放视频 | 黄色毛片在线观看 | 久久久久久久久久久久久久av | 国产精品欧美日韩在线观看 | 91视频免费网址 |