日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

filter执行先后问题_filter的执行顺序是怎样的?

發(fā)布時(shí)間:2023/12/19 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 filter执行先后问题_filter的执行顺序是怎样的? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.引言

我們在編寫javaweb程序的時(shí)候,時(shí)常會用filter這個(gè)組件,它能將我們一些通用邏輯抽取出來,在servlet執(zhí)行業(yè)務(wù)邏輯之前運(yùn)行,

達(dá)到簡化代碼和復(fù)用的目的.比如最常用的場景全站編碼和登錄驗(yàn)證功能。

servlet3.0以前我們只能通過web.xml的方式配置filter,并且多個(gè)filter的執(zhí)行順序是根據(jù)你web.xml中書寫順序來決定的.

servlet3.0以后,提供了注解的方式注入filter,只需要在filter類上加上@WebFilter()注解即可,大大的簡化了開發(fā)復(fù)雜度.

2.拋出問題

注解的方式書寫的filter的執(zhí)行順序又是如何的呢?

網(wǎng)上的很多資料都說是根據(jù)filter的類名來決定,也有說是根據(jù)filter的注解的name屬性值的字母順序來決定的.

對不對呢?

2.驗(yàn)證問題

我們創(chuàng)建了三個(gè)filter 來驗(yàn)證此問題

filter1號

package com.jk1123.web.filter.demo01;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/*")

public class OrderFilter1 implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

System.out.println("orderFilter1執(zhí)行了..");

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

}

}

filter2號

package com.jk1123.web.filter.demo02;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/*")

public class OrderFilter2 implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

System.out.println("orderFilter2執(zhí)行了..");

//這是放行

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

}

}

filter3號

package com.jk1123.web.filter.demo03;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/*")

public class OrderFilter3 implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

System.out.println("orderFilter3執(zhí)行了..");

//這是放行

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

}

}

配上一個(gè)servlet 來訪問試試

package com.jk1123.web.servlet;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/foo")

public class FooServlet extends HttpServlet {

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.getWriter().print("foo servlet");

}

}

驗(yàn)證結(jié)果:

3.查看源碼

可以從上面驗(yàn)證看出 好像并不是根據(jù)類名或者filter的name屬性的字母排序執(zhí)行,那到底是根據(jù)什么執(zhí)行的呢?

點(diǎn)開源碼,我們一點(diǎn)點(diǎn)探尋它的秘密。

需要搞清楚如下問題

1.filterChain是什么時(shí)候執(zhí)行的呢?

2.filterChain中的filter來源何處?

3.standardContext什么時(shí)候開始收集的過濾器集合

我們先查詢第一段源碼 解密filterChain是什么時(shí)候執(zhí)行的

//在org.apache.catalina.core.StandardWrapperValve 類中有如下一個(gè)方法

public final void invoke(Request request, Response response)

throws IOException, ServletException {

//省略掉大段無關(guān)代碼

//0.生命servlet對象

Servlet servlet = null;

/**

* 省略一大段無關(guān)代碼

*/

try {

if (!unavailable) {

//1.這里創(chuàng)建正在訪問的servlet對象

servlet = wrapper.allocate();

}

} catch (UnavailableException e) {

//省略掉大段無關(guān)代碼

}

//省略大段無關(guān)代碼

//2.創(chuàng)建過濾器鏈對象

ApplicationFilterChain filterChain =

ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

try {

if ((servlet != null) && (filterChain != null)) {

// Swallow output if needed

if (context.getSwallowOutput()) {

//省略掉大段無關(guān)代碼

} else {

if (request.isAsyncDispatching()) {

request.getAsyncContextInternal().doInternalDispatch();

} else {

//3.執(zhí)行過濾鏈對象doFilter方法

filterChain.doFilter

(request.getRequest(), response.getResponse());

}

}

}

} catch (ClientAbortException | CloseNowException e) {

//省略掉大段無關(guān)代碼

}

}

我們一會兒回過頭來看它是如何創(chuàng)建過濾器鏈對象的代碼,我們先來看他是如何執(zhí)行過濾器鏈的,

過濾器鏈對象的實(shí)現(xiàn)為:

package org.apache.catalina.core;

//我們只保留 跟執(zhí)行序列有關(guān)的代碼

public final class ApplicationFilterChain implements FilterChain {

//當(dāng)前正在執(zhí)行的filter索引

private int pos = 0;

//總共有多少個(gè)filter匹配上了

private int n = 0;

//關(guān)聯(lián)的要執(zhí)行的servlet對象

private Servlet servlet = null;

//匹配上的filter數(shù)組

private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];

@Override

public void doFilter(ServletRequest request, ServletResponse response)

throws IOException, ServletException {

if( Globals.IS_SECURITY_ENABLED ) {

//刪除無關(guān)代碼

} else {

//0.執(zhí)行內(nèi)容的doFilter方法

internalDoFilter(request,response);

}

}

private void internalDoFilter(ServletRequest request,

ServletResponse response)

throws IOException, ServletException {

// Call the next filter if there is one

if (pos < n) {

//這個(gè)地方主義有個(gè)pos++ 進(jìn)來一次 ++一次

ApplicationFilterConfig filterConfig = filters[pos++];

try {

Filter filter = filterConfig.getFilter();

//刪除大段無關(guān)代碼

if( Globals.IS_SECURITY_ENABLED ) {

//刪除大段無關(guān)代碼

} else {

//執(zhí)行過濾器鏈中的過濾器的doFilter方法

//而我們的過濾器中滿足條件后 放行 放行就會跳轉(zhuǎn)回來執(zhí)行過濾器鏈的

//的doFilter 也就是又回來執(zhí)行第二個(gè)

filter.doFilter(request, response, this);

}

} catch (IOException | ServletException | RuntimeException e) {

throw e;

} catch (Throwable e) {

e = ExceptionUtils.unwrapInvocationTargetException(e);

ExceptionUtils.handleThrowable(e);

throw new ServletException(sm.getString("filterChain.filter"), e);

}

return;

}

try {

//刪除大段無關(guān)代碼

// Use potentially wrapped request from this point

if ((request instanceof HttpServletRequest) &&

(response instanceof HttpServletResponse) &&

Globals.IS_SECURITY_ENABLED ) {

//刪除大段無關(guān)代碼

} else {

//如果沒有需要執(zhí)行的filter就會執(zhí)行 servlet的service方法 也就是我們寫的業(yè)務(wù)邏輯

servlet.service(request, response);

}

} catch (IOException | ServletException | RuntimeException e) {

throw e;

} catch (Throwable e) {

e = ExceptionUtils.unwrapInvocationTargetException(e);

ExceptionUtils.handleThrowable(e);

throw new ServletException(sm.getString("filterChain.servlet"), e);

} finally {

if (ApplicationDispatcher.WRAP_SAME_OBJECT) {

lastServicedRequest.set(null);

lastServicedResponse.set(null);

}

}

}

}

從filterChain類的源碼可以看出底層是包含了 所匹配上的filter數(shù)組 也就是添加進(jìn)去匹配上過濾器對象是有序的 添加的時(shí)候就決定了!!!

那么它是什么時(shí)候添加的呢?

2.filterChain中的filter來源何處?

其實(shí)我們在在org.apache.catalina.core.StandardWrapperValve ?類的invoke方法中

ApplicationFilterChain filterChain =

ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

點(diǎn)開這段代碼查詢把!

public static ApplicationFilterChain createFilterChain(ServletRequest request,

Wrapper wrapper, Servlet servlet) {

// If there is no servlet to execute, return null

if (servlet == null)

return null;

// 在這里創(chuàng)建ApplicationFilterChain 對象

//但是對象里還沒有filter對象

ApplicationFilterChain filterChain = null;

if (request instanceof Request) {

Request req = (Request) request;

if (Globals.IS_SECURITY_ENABLED) {

// Security: Do not recycle

filterChain = new ApplicationFilterChain();

} else {

filterChain = (ApplicationFilterChain) req.getFilterChain();

if (filterChain == null) {

filterChain = new ApplicationFilterChain();

req.setFilterChain(filterChain);

}

}

} else {

// Request dispatcher in use

filterChain = new ApplicationFilterChain();

}

filterChain.setServlet(servlet);

filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

// Acquire the filter mappings for this Context

StandardContext context = (StandardContext) wrapper.getParent();

//獲取ServletContext對象 注冊的所有的filter數(shù)組

FilterMap filterMaps[] = context.findFilterMaps();

// If there are no filter mappings, we are done

if ((filterMaps == null) || (filterMaps.length == 0))

return filterChain;

// Acquire the information we will need to match filter mappings

DispatcherType dispatcher =

(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

String requestPath = null;

Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);

if (attribute != null){

requestPath = attribute.toString();

}

String servletName = wrapper.getName();

//這里開始遍歷 filterMaps數(shù)組根據(jù)請求路徑匹配添加

for (int i = 0; i < filterMaps.length; i++) {

if (!matchDispatcher(filterMaps[i] ,dispatcher)) {

continue;

}

if (!matchFiltersURL(filterMaps[i], requestPath))

continue;

ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)

context.findFilterConfig(filterMaps[i].getFilterName());

if (filterConfig == null) {

// FIXME - log configuration problem

continue;

}

filterChain.addFilter(filterConfig);

}

// Add filters that match on servlet name second

for (int i = 0; i < filterMaps.length; i++) {

if (!matchDispatcher(filterMaps[i] ,dispatcher)) {

continue;

}

if (!matchFiltersServlet(filterMaps[i], servletName))

continue;

ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)

context.findFilterConfig(filterMaps[i].getFilterName());

if (filterConfig == null) {

// FIXME - log configuration problem

continue;

}

filterChain.addFilter(filterConfig);

}

// Return the completed filter chain

return filterChain;

}

可以看出在創(chuàng)建filterChain對象時(shí)候,從ServletContext獲取所有注冊的filter的數(shù)組 取出需要的添加到這次請求創(chuàng)建的filterChain對象中

而且servletContext對象的注冊的所有的過濾器本身就是一個(gè)數(shù)組 本身就是有序的,所以遍歷匹配的時(shí)候,也就是有序的!

3、ServletContext什么時(shí)候開始收集的數(shù)組,從哪來的呢?

這個(gè)要從tomcat啟動的時(shí)候來看了!

而StandardContext創(chuàng)建完成以后就要開始初始化操作了!

StandardContext.startInternal()方法---->fireLifecycleEvent()方法-->ContextConfig.lifecycleEvent()-->ContextConfig.lifecycleEventcon-->ContextConfig.con.figureStart()-->ContextConfig.webConfig()

好了我們現(xiàn)在查看該方法:

protected void webConfig() {

WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),

context.getXmlValidation(), context.getXmlBlockExternal());

Set defaults = new HashSet<>();

defaults.add(getDefaultWebXmlFragment(webXmlParser));

//創(chuàng)建了web.xml 配置文件對象

//也就是它就代表我們項(xiàng)目的配置相關(guān)的信息

WebXml webXml = createWebXml();

// Parse context level web.xml

InputSource contextWebXml = getContextWebXmlSource();

//解析web.xml 配置文件

//發(fā)現(xiàn)配置文件中的 filter servlet listener等配置

//而xml的解析是從上到下 所以你在web.xml 配置filter

//得到filter集合就是有序的

if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {

ok = false;

}

ServletContext sContext = context.getServletContext();

//省略大段無關(guān)代碼

if ?(!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {

// Steps 4 & 5.

//掃描編譯的類文件 尋找注解方式書寫的servlet filter listener

processClasses(webXml, orderedFragments);

}

//省略大段無關(guān)代碼

}

從上面代碼 可以看出web,xml配置的filter肯定是有序的了 解析的時(shí)候 就會收集到webXml對象的

//采用的是linkedHashset來存儲的 是有序的

private final Set filterMaps = new LinkedHashSet<>();

解析xml過程我們就不看了 人家才是的digester的xml解析框架來做.

我們來查看processClasses(webXml, orderedFragments); 這個(gè)方法是解析注解用的

protected void processClasses(WebXml webXml, Set orderedFragments) {

// Step 4. Process /WEB-INF/classes for annotations and

// @HandlesTypes matches

Map javaClassCache = new HashMap<>();

if (ok) {

//獲取項(xiàng)目下的類路徑

WebResource[] webResources =

context.getResources().listResources("/WEB-INF/classes");

for (WebResource webResource : webResources) {

// Skip the META-INF directory from any JARs that have been

// expanded in to WEB-INF/classes (sometimes IDEs do this).

if ("META-INF".equals(webResource.getName())) {

continue;

}

//開始根據(jù)注解解析了

processAnnotationsWebResource(webResource, webXml,

webXml.isMetadataComplete(), javaClassCache);

}

}

// Step 5. Process JARs for annotations and

// @HandlesTypes matches - only need to process those fragments we

// are going to use (remember orderedFragments includes any

// container fragments)

if (ok) {

processAnnotations(

orderedFragments, webXml.isMetadataComplete(), javaClassCache);

}

// Cache, if used, is no longer required so clear it

javaClassCache.clear();

}

查看processAnnotationsWebResource方法

protected void processAnnotationsWebResource(WebResource webResource,

WebXml fragment, boolean handlesTypesOnly,

Map javaClassCache) {

//看看是否是個(gè)目錄

if (webResource.isDirectory()) {

WebResource[] webResources =

webResource.getWebResourceRoot().listResources(

webResource.getWebappPath());

if (webResources.length > 0) {

if (log.isDebugEnabled()) {

log.debug(sm.getString(

"contextConfig.processAnnotationsWebDir.debug",

webResource.getURL()));

}

//遍歷目錄

for (WebResource r : webResources) {

//遞歸處理

processAnnotationsWebResource(r, fragment, handlesTypesOnly, javaClassCache);

}

}

} else if (webResource.isFile() &&

webResource.getName().endsWith(".class")) {

try (InputStream is = webResource.getInputStream()) {

//如果是類文件的話 開始處理

processAnnotationsStream(is, fragment, handlesTypesOnly, javaClassCache);

} catch (IOException e) {

log.error(sm.getString("contextConfig.inputStreamWebResource",

webResource.getWebappPath()),e);

} catch (ClassFormatException e) {

log.error(sm.getString("contextConfig.inputStreamWebResource",

webResource.getWebappPath()),e);

}

}

}

查看processAnnotationsStream方法

protected void processAnnotationsStream(InputStream is, WebXml fragment,

boolean handlesTypesOnly, Map javaClassCache)

throws ClassFormatException, IOException {

ClassParser parser = new ClassParser(is);

JavaClass clazz = parser.parse();

checkHandlesTypes(clazz, javaClassCache);

if (handlesTypesOnly) {

return;

}

//處理開始

processClass(fragment, clazz);

}

protected void processClass(WebXml fragment, JavaClass clazz) {

AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();

if (annotationsEntries != null) {

String className = clazz.getClassName();

for (AnnotationEntry ae : annotationsEntries) {

String type = ae.getAnnotationType();

if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {

processAnnotationWebServlet(className, ae, fragment);

//判斷是否webFilter注解 如果是就添加到 webxml配置對象中

}else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {

processAnnotationWebFilter(className, ae, fragment);

}else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {

fragment.addListener(className);

} else {

// Unknown annotation - ignore

}

}

}

}

從上面可以看出原來掃描類路徑的時(shí)候,就是先遍歷文件夾 遍歷文件夾下類文件 反射查看是否是一個(gè)帶有WebFilter注解的類

如果是就添加到web.xml中set集合中,而那個(gè)set集合是有序的linkedset

所有順序就是遞歸遍歷文件夾的順序 一切就看 遞歸的時(shí)候如何獲取下級文件夾的代碼了 看它是否進(jìn)行排序了?

也就是說由如下代碼決定的

WebResource[] webResources =

webResource.getWebResourceRoot().listResources(

webResource.getWebappPath());

點(diǎn)開這段代碼

protected WebResource[] listResources(String path, boolean validate) {

if (validate) {

path = validate(path);

}

String[] resources = list(path, false);

WebResource[] result = new WebResource[resources.length];

for (int i = 0; i < resources.length; i++) {

if (path.charAt(path.length() - 1) == '/') {

result[i] = getResource(path + resources[i], false, false);

} else {

result[i] = getResource(path + '/' + resources[i], false, false);

}

}

return result;

}

//繼續(xù)

private String[] list(String path, boolean validate) {

if (validate) {

path = validate(path);

}

// Set because we don't want duplicates

// LinkedHashSet to retain the order. It is the order of the

// WebResourceSet that matters but it is simpler to retain the order

// over all of the JARs.

HashSet result = new LinkedHashSet<>();

for (List list : allResources) {

for (WebResourceSet webResourceSet : list) {

if (!webResourceSet.getClassLoaderOnly()) {

String[] entries = webResourceSet.list(path);

for (String entry : entries) {

result.add(entry);

}

}

}

}

return result.toArray(new String[result.size()]);

}

//繼續(xù)

public String[] list(String path) {

checkPath(path);

String webAppMount = getWebAppMount();

if (path.startsWith(webAppMount)) {

File f = file(path.substring(webAppMount.length()), true);

if (f == null) {

return EMPTY_STRING_ARRAY;

}

//就到這里了 我們可以看到 它沒有排序就是調(diào)用了

//file類的list方法

String[] result = f.list();

if (result == null) {

return EMPTY_STRING_ARRAY;

} else {

return result;

}

} else {

if (!path.endsWith("/")) {

path = path + "/";

}

if (webAppMount.startsWith(path)) {

int i = webAppMount.indexOf('/', path.length());

if (i == -1) {

return new String[] {webAppMount.substring(path.length())};

} else {

return new String[] {

webAppMount.substring(path.length(), i)};

}

}

return EMPTY_STRING_ARRAY;

}

}

來來打開file類的list方法看看

所以最終 web.xml收集到所有filter的set集合 如果采用的是注解方式 沒有任何順序可言的.

然后接下來的代碼我們就不看了無非就是將收集到的filter集合轉(zhuǎn)換成數(shù)組 設(shè)置給StandardContext對象

4.得出結(jié)論

如果采用web.xml寫的filter執(zhí)行順序跟書寫順序有關(guān)

而采用注解方式的是沒有順序可言的!!!!

而采用注解方式的是沒有順序可言的!!!!

而采用注解方式的是沒有順序可言的!!!!

實(shí)踐出真知!切記人云亦云!有問題找源碼!!!

猜你喜歡:

Java中級程序員培訓(xùn)課程

總結(jié)

以上是生活随笔為你收集整理的filter执行先后问题_filter的执行顺序是怎样的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 美女又大又黄 | 国产精品视频1区 | 搡老熟女老女人一区二区 | 久久久高清免费视频 | 久久精品123 | 五月天激情社区 | 男女做受视频 | 亚洲视频2 | 美女超碰在线 | 久久综合一区 | 久久亚洲精 | 理论片大全免费理伦片 | 国产免费91 | 三级成人在线 | 亚洲视频在线网 | 亚洲在线观看视频 | 深夜福利成人 | 精品无码久久久久久久久久 | 婷婷深爱网 | 在线91观看 | 久久久久久在线观看 | 亚洲精品久久 | 插插综合视频 | 国产特级毛片aaaaaa | 亚洲小说区图片区 | 俄罗斯精品一区二区三区 | 亚洲性生活视频 | av在线天天 | 欧洲精品免费一区二区三区 | 视频二区 | 久久久亚洲精品无码 | 91小宝寻花一区二区三区 | 久久中文字幕电影 | 啪啪激情网 | 69式视频| 欧美色图影院 | 亚洲射图| 五月婷婷欧美 | 最近中文字幕在线免费观看 | 国产美女精品一区二区三区 | 一区二区三区精品在线观看 | 人体毛片 | 精品一区二区亚洲 | 绝顶高潮videos合集 | 免费看黄在线网站 | 大地资源中文在线观看免费版 | 国产一卡二卡三卡 | 一级黄色大毛片 | 亚洲一区二区在线免费 | 香蕉av在线播放 | aaaa黄色 | 国产精品传媒在线观看 | 国产精品一区二区三区在线看 | 中文av网站 | 中文字字幕在线中文乱码电影 | 秋霞毛片少妇激情免费 | 久久激情网 | 亚洲色欧美另类 | 午夜欧美成人 | 成人h动漫精品一区二区下载 | 日本xx视频免费观看 | 视频一区二区在线播放 | 日批黄色片 | 精品视频免费在线 | 日韩av在线免费播放 | 4438x全国最大成人网 | 五月激情六月 | 亚洲男人在线天堂 | 国产精品麻豆入口 | 香蕉在线影院 | 少妇的被肉日常np | 九九视频免费在线观看 | 成人污污www网站免费丝瓜 | 日本乱码视频 | 国产精品成人av性教育 | 国产亚洲精品久久久久久久久动漫 | 毛片免费全部无码播放 | 免费无遮挡在线观看视频网站 | 性生交大片免费看狂欲 | 日韩av一二三区 | 激情999| chinese麻豆新拍video | 久久人人爽天天玩人人妻精品 | 亚洲精品视频在线观看免费视频 | 欧美一区永久视频免费观看 | 天堂а√在线中文在线鲁大师 | 国产精品久久亚洲 | 中文字幕五区 | 欧美激情校园春色 | 黄色在线播放 | 无码精品一区二区三区在线 | 午夜爱爱毛片xxxx视频免费看 | 久久国产精品久久久久久 | 玉米地疯狂的吸允她的奶视频 | 无码精品久久久久久久 | 亚洲精品日产精品乱码不卡 | 色吧综合网 | 欧美鲁鲁 | 麻豆av免费观看 |