<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kingpub

    海內(nèi)存知己,博客若比鄰

     

    用Spring JMS使異步消息變得簡(jiǎn)單

    作者:Srini;David_w_johnson
    原文:http://www.onjava.com/pub/a/onjava/2006/02/22/asynchronous-messaging-with-spring-jms.html?

    異步處理通信是面向服務(wù)架構(gòu)(SOA)的重要部分,因?yàn)槠髽I(yè)中的許多系統(tǒng)通信,尤其是跟外部系統(tǒng)通信本來(lái)就是異步的。Java消息服務(wù)(JMS)就是用來(lái)編寫異步消息J2EE應(yīng)用的API。使用JMS API的傳統(tǒng)消息實(shí)現(xiàn)涉及到象這樣的一些步驟:查找對(duì)列連接工廠、隊(duì)列資源以及在實(shí)際發(fā)送和接受消息前,創(chuàng)建JMS會(huì)話(JMS session)。

    Spring framework簡(jiǎn)化了用JEE組件(包括JMS)開(kāi)發(fā)JMS應(yīng)用的工作。它提供了一個(gè)模板機(jī)制來(lái)隱藏典型的JMS實(shí)現(xiàn)細(xì)節(jié),所以開(kāi)發(fā)者可以專注于消息處理任務(wù)而不用擔(dān)心怎樣創(chuàng)建、訪問(wèn)和釋放JMS資源。

    本文用一個(gè)運(yùn)行在JBoss MQ server上的簡(jiǎn)單Web應(yīng)用概述了Spring JMS API和怎樣使用它異步處理(發(fā)送和接受)消息。我將對(duì)比JMS實(shí)現(xiàn)的傳統(tǒng)方法和Spring JMS實(shí)現(xiàn)方法,以顯示使用Spring JMS來(lái)處理消息是多么的簡(jiǎn)單和靈活。

    異步消息和SOA

    現(xiàn)實(shí)世界中,大多數(shù)Web請(qǐng)求是同步處理的。例如,當(dāng)用戶登陸一個(gè)站點(diǎn),他或她輸入用戶名和口令以及服務(wù)器識(shí)別登陸憑證。如果身份驗(yàn)證成功,程序讓用戶進(jìn)入站點(diǎn)。這里,登陸請(qǐng)求從客戶端被接受后,立即被處理。信用卡授權(quán)也是一個(gè)同步處理的例子;僅當(dāng)服務(wù)器核實(shí)了發(fā)送進(jìn)來(lái)的信用卡號(hào)是有效并且該客戶的帳號(hào)有足夠的信用額度后,才允許客戶繼續(xù)進(jìn)行下一步動(dòng)作。讓我們來(lái)考察一下訂單處理系統(tǒng)中的支付結(jié)算步驟。一旦系統(tǒng)核實(shí)了那個(gè)用戶的信用卡信息是正確的,而且?guī)羯嫌凶銐虻馁Y金,那么不需要等到支付細(xì)節(jié)和轉(zhuǎn)帳最終完成。支付結(jié)算用異步方式處理,如此客戶便可以繼續(xù)進(jìn)行結(jié)帳處理。

    與典型的同步請(qǐng)求相比,異步處理用于需要長(zhǎng)時(shí)間來(lái)處理的請(qǐng)求。異步處理的另外一個(gè)例子是住房貸款處理應(yīng)用中,處理提交到AUS(Automated Underwriting System)的貸款請(qǐng)求。貸款人提交貸款申請(qǐng)后,抵押公司發(fā)送請(qǐng)求到AUS取得信用歷史信息。因?yàn)樵撜?qǐng)求要取得綜合詳細(xì)的信用報(bào)告如貸款人當(dāng)前和過(guò)去的信用帳戶,最近的支付以及其它金融詳細(xì)信息,所以從請(qǐng)求到獲得響應(yīng)常常需要很長(zhǎng)時(shí)間。對(duì)客戶端程序來(lái)說(shuō)開(kāi)一個(gè)到服務(wù)器的連接并且長(zhǎng)時(shí)間等待響應(yīng)是沒(méi)有意義的。于是就有了異步通信;也就是,一旦請(qǐng)求被提交,它就被放入隊(duì)列里面并且客戶斷開(kāi)服務(wù)器連接。然后,AUS服務(wù)從特定隊(duì)列摘取請(qǐng)求,處理它,把結(jié)果消息放入另外一個(gè)消息隊(duì)列。最后客戶程序從消息隊(duì)列摘取響應(yīng)結(jié)果繼續(xù)處理信用歷史結(jié)果信息。

    JMS

    如果用過(guò)JMS的話,會(huì)發(fā)現(xiàn)它類似寫JDBC或JCA代碼。它有創(chuàng)建或檢索JMS資源的樣板代碼,每當(dāng)你需要編寫一個(gè)新類來(lái)發(fā)送或接受消息時(shí),都得重復(fù)編寫那個(gè)樣本代碼。下面列出了傳統(tǒng)JMS實(shí)現(xiàn)涉及的步驟:
    1、創(chuàng)建JNDI初始上下文context;
    2、從JNDI上下文獲得隊(duì)列連接工廠;
    3、從隊(duì)列連接工廠取得隊(duì)列Queue;
    4、創(chuàng)建一個(gè)Session對(duì)象;
    5、創(chuàng)建一個(gè)發(fā)送或接受對(duì)象;
    6、利用第5部創(chuàng)建的發(fā)送或接受對(duì)象發(fā)送或接受消息;
    7、處理完消息后,關(guān)閉所有JMS資源。

    如你所見(jiàn),只有第6步是處理消息的步驟。其他步驟都只是管理JMS資源,與實(shí)際業(yè)務(wù)需求無(wú)關(guān),但開(kāi)發(fā)者不得不編寫和維護(hù)那些附加步驟代碼。

    Spring JMS

    Spring框架提供一個(gè)模板機(jī)制來(lái)隱藏Java API細(xì)節(jié)。JEE開(kāi)發(fā)者可用JDBCTemplate 和JNDITemplate類來(lái)分別訪問(wèn)后端數(shù)據(jù)庫(kù)和JEE資源(數(shù)據(jù)源,連接池)。JMS沒(méi)有異常。Spring提供了JMSTemplate類,所以開(kāi)發(fā)者不必為JMS實(shí)現(xiàn)編寫樣本代碼。當(dāng)開(kāi)發(fā)JMS應(yīng)用時(shí),Spring提供了一下一些優(yōu)勢(shì):
    1、提供了一個(gè)JMS的抽象API,簡(jiǎn)化了JMS的使用。如:訪問(wèn)目的地(隊(duì)列或主體)和出版消息到特定目的地。
    2、JEE開(kāi)發(fā)者不必關(guān)心JMS不同版本之間的差異(如JMS 1.0.2 同 JMS 1.1);
    3、開(kāi)發(fā)者不必特定地處理JMS異常,因?yàn)镾pring為JMS代碼拋出的任何JMS異常提供了一個(gè)unchecked異常。

    一旦你在JMS應(yīng)用中開(kāi)始使用Spring,你將會(huì)欣賞到異步消息處理的簡(jiǎn)易性。Spring JMS框架提供了各種java類使JMS開(kāi)發(fā)變得簡(jiǎn)單。

    image
    表1,Spring JMS類

    隨后的部分,我將詳細(xì)解釋表1中的類(如JmsTemplate, DestinationResolver,和 MessageConverter)。


    JMSTemplate

    JmsTemplate提供了幾個(gè)helper方法來(lái)執(zhí)行基本操作。開(kāi)始使用JmsTemplate前,有必要知道JMS提供者支持哪種JMS規(guī)范。JBoss AS 4.0.2 和 WebLogic 8.1服務(wù)器支持JMS1.0.2規(guī)范。WebLogic 服務(wù)器 9.0包含JMS1.1支持。JMS1.1統(tǒng)一了PTP和Pub/Sub編程接口。有了這個(gè)改變,開(kāi)發(fā)者可以創(chuàng)建一個(gè)事務(wù)會(huì)話,然后在同一個(gè)JMS事務(wù)中,從Queue(PTP)接受消息和發(fā)送一個(gè)消息到Topic(Pub/Sub)。JMS1.1向后兼容JMS1.0,因此基于JMS1.0編寫的代碼仍然能跟JMS1.1工作。

    JmsTemplate提供各種方法來(lái)接收和發(fā)送消息。表2是方法列表。

    image
    表2。JMS模板方法

    使用JNDI上下文存儲(chǔ)和檢索目的地。當(dāng)配置Spring應(yīng)用上下文時(shí),我們用JndiObjectFactoryBean獲得JMS目的地引用。DestinationResolver用來(lái)解析目的地名稱到一個(gè)JMS目的地,當(dāng)應(yīng)用有許多目的地時(shí),那是很有幫助的。DynamicDestinationResolver(缺省DestinationResolver實(shí)現(xiàn))用于解析動(dòng)態(tài)目的地。

    MessageConverter接口定義了java對(duì)象和JMS消息之間轉(zhuǎn)換的契約。使用轉(zhuǎn)換器,應(yīng)用代碼可以專注于業(yè)務(wù)對(duì)象,不用操心它是如何代表JMS消息的。SimpleMessageConverter(和SimpleMessageConverter102)是缺省MessageConverter實(shí)現(xiàn)。它們用于將String、字節(jié)數(shù)組((byte[])、Map、Serializable對(duì)象分別轉(zhuǎn)換成JMS TextMessage、JMS BytesMessage,JMS MapMessage,JMS ObjectMessage。你可以編寫MessageConverter接口的定制實(shí)現(xiàn)并結(jié)合XML綁定框架如JAXB, Castor, Commons Digester, XMLBeans, 或 XStream來(lái)轉(zhuǎn)換XML文檔到TextMessage。

    樣本應(yīng)用

    我將用一個(gè)樣本貸款應(yīng)用處理系統(tǒng)(叫LoanProc)來(lái)說(shuō)明怎樣在JMS應(yīng)用中使用Spring。作為貸款處理的一部分,LoanProc發(fā)送貸款詳細(xì)資料(loan ID, borrower name, borrower's SSN, loan expiration date, and loan amount)從AUS系統(tǒng)請(qǐng)求信貸歷史。為讓例子簡(jiǎn)單一點(diǎn),我們將基于兩個(gè)參數(shù):信用評(píng)分和貸款數(shù)量來(lái)獲得信貸歷史詳細(xì)資料。讓我們假定處理信用檢查請(qǐng)求的業(yè)務(wù)規(guī)則如下:
    1、如果貸款數(shù)量等于或小于$500,000,那么貸款人必須至少有一個(gè)“good”信用(例如,貸款人的信用評(píng)分在680到699之間);
    2、如果貸款數(shù)量超過(guò)$500,000,那么貸款人必須至少要有一個(gè)“very good”信用,這意味他/她的信用評(píng)分超過(guò)700。

    貸款應(yīng)用Use Case

    貸款請(qǐng)求處理Use Case由下列步驟組成:
    1、用戶在貸款申請(qǐng)web頁(yè)面輸入貸款詳細(xì)資料并提交貸款申請(qǐng);
    2、然后程序發(fā)送貸款詳細(xì)資料到AUS系統(tǒng)取得信用歷史詳細(xì)資料。用發(fā)送請(qǐng)求到名叫CreditRequestSendQueue的消息隊(duì)列來(lái)完成。
    3、AUS系統(tǒng)從隊(duì)列摘取貸款詳細(xì)資料并用貸款參數(shù)來(lái)從數(shù)據(jù)庫(kù)檢索信用歷史信息;
    4、然后AUS系統(tǒng)用找到的貸款人信用歷史信息創(chuàng)建一個(gè)新的消息并發(fā)送到名叫CreditRequestReceiveQueue的消息隊(duì)列;
    5、最后LoanProc從接收消息隊(duì)列摘取響應(yīng)消息并處理貸款申請(qǐng),決定申請(qǐng)是被核準(zhǔn)還是拒絕。

    應(yīng)用中,在同樣的JBoss MQ server中配置了兩個(gè)消息隊(duì)列。Use Case用序列圖1表示如下:

    image
    圖1:貸款處理應(yīng)用的序列圖

    技術(shù)

    表3列出了例子應(yīng)用中用到的一些技術(shù)和開(kāi)源框架

    image
    表3,JMS應(yīng)用中用到的框架

    使用Hermes 的JMS資源設(shè)置

    為異步處理消息,首先,我們需要消息隊(duì)列來(lái)發(fā)送和接收消息。我們?cè)贘Boss中使用xml配置文件創(chuàng)建消息隊(duì)列并且用JMS控制臺(tái)來(lái)瀏覽隊(duì)列詳細(xì)資料。清單1顯示了XML配置文件JMS配置片斷。(這個(gè)片斷可以被添加到%JBOSS_HOME%\server\all\deploy-hasingleton\jms目錄下的jbossmq-destinations-service.xml文件中。)

    清單1,JBoss MQ服務(wù)器中JMS隊(duì)列配置

    <!--??Credit Request Send Queue??-->
    <mbean code="org.jboss.mq.server.jmx.Queue"
    ??name="jboss.mq.destination:service=Queue,name=CreditRequestSendQueue">
    ??<depends optional-attribute-name="DestinationManager">
    ????jboss.mq:service=DestinationManager
    ??</depends>
    </mbean>

    <!--??Credit Request Receive Queue??-->
    <mbean code="org.jboss.mq.server.jmx.Queue"
    ??name="jboss.mq.destination:service=Queue,name=CreditRequestReceiveQueue">
    ??<depends optional-attribute-name="DestinationManager">
    ????jboss.mq:service=DestinationManager
    ??</depends>
    </mbean>



    現(xiàn)在,讓我們看看怎么使用一個(gè)叫做Hermes的JMS工具瀏覽消息隊(duì)列。Hermes是一個(gè)Java Swing應(yīng)用,它能創(chuàng)建、管理和監(jiān)控JMS提供者中的JMS destination。這樣的JMS提供者有JBossMQ, WebSphereMQ, ActiveMQ 和 Arjuna。從website下載Hermes并解壓zip文件到一個(gè)本地目錄(如c:\dev\tools\hermes)。一旦安裝,雙擊hermes.bat (在bin目錄)啟動(dòng)程序。

    為在Hermes中配置JBossMQ服務(wù)器,參考Hermes站點(diǎn)上的demo。它一步一步形象說(shuō)明了JBoss MQ的配置。當(dāng)配置一個(gè)新的JNDI初始上下文時(shí),輸入下面的配置信息。

    ?providerURL = jnp://localhost:1099
    ?initialContextFactory = org.jnp.interfaces.NamingContextFactory
    ?urlPkgPrefixes = org.jnp.interfaces:org.jboss.naming
    ?securityCredentials = admin
    ?securityPrincipal = admin

    當(dāng)創(chuàng)建一個(gè)新destinations時(shí),輸入queue/CreditRequestSendQueue 和 queue/CreditRequestReceiveQueue。圖2顯示了JMS控制臺(tái)主屏幕,它顯示了為樣本JMS應(yīng)用創(chuàng)建的新消息。

    image
    圖2.Hermes中所有destinations的截屏


    圖3是消息發(fā)送者發(fā)送一些消息到CreditRequestSendQueue后,Hermes JMS控制臺(tái)顯示的消息隊(duì)列詳細(xì)資料。你能看到這里隊(duì)列中有5個(gè)消息并且控制臺(tái)顯示了消息的詳細(xì)信息如message ID、message destination、time stamp、和實(shí)際的消息。

    image
    圖3.Hermes中隊(duì)列詳細(xì)資料截屏


    使用Spring JMS,異步消息變得簡(jiǎn)單

    用在樣本應(yīng)用中的這些消息隊(duì)列名和其它JMS以及JNDI參數(shù)如下表4所示。

    image
    表4,Spring JMS配置參數(shù)


    Spring配置

    已經(jīng)有了運(yùn)行樣本應(yīng)用所需的JMS destinations,現(xiàn)在該是進(jìn)入用XML Spring配置文件(叫做spring-jms.xml)裝配JMS組件的細(xì)節(jié)的時(shí)候了。用IOC設(shè)計(jì)模式中的setter依賴注入原理裝入這些組件。讓我們仔細(xì)看看組件,為每一個(gè)JMS組件顯示了一個(gè)XML配置片斷。

    JNDI上下文是獲取JMS資源的入口,所以我們首先配置一個(gè)JNDI模板。清單2顯示了一名為jndiTemplate的Spring bean,它具有取得JNDI初始上下文必須的常用參數(shù)。

    清單2,JNDI上下文模板

    <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    ????<property name="environment">
    ????????<props>
    ????????????<prop key="java.naming.factory.initial">
    ????????????????org.jnp.interfaces.NamingContextFactory
    ????????????</prop>
    ????????????<prop key="java.naming.provider.url">
    ????????????????localhost
    ????????????</prop>
    ????????????<prop key="java.naming.factory.url.pkgs">
    ????????????????org.jnp.interfaces:org.jboss.naming
    ????????????</prop>
    ????????</props>
    ????</property>
    </bean>



    下一步,我們配置隊(duì)列連接工廠。清單3顯示了隊(duì)列連接工廠。

    清單3,JMS對(duì)了連接工廠配置

    <bean id="jmsQueueConnectionFactory"
    ??????class="org.springframework.jndi.JndiObjectFactoryBean">
    ????<property name="jndiTemplate">
    ????????<ref bean="jndiTemplate"/>
    ????</property>
    ????<property name="jndiName">
    ????????<value>UIL2ConnectionFactory</value>
    ????</property>
    </bean>



    我們定義了兩個(gè)JMS destinations來(lái)發(fā)送和接收消息。清單4和清單5顯示了這些細(xì)節(jié)。

    清單4,發(fā)送隊(duì)列配置

    <bean id="sendDestination"
    ????class="org.springframework.jndi.JndiObjectFactoryBean">
    ????<property name="jndiTemplate">
    ????????<ref bean="jndiTemplate"/>
    ????</property>
    ????<property name="jndiName">
    ????????<value>queue/CreditRequestSendQueue</value>
    ????</property>
    </bean>



    清單5,接收隊(duì)列配置

    <bean id="receiveDestination"
    ????class="org.springframework.jndi.JndiObjectFactoryBean">
    ????<property name="jndiTemplate">
    ????????<ref bean="jndiTemplate"/>
    ????</property>
    ????<property name="jndiName">
    ????????<value>queue/CreditReqeustReceiveQueue</value>
    ????</property>
    </bean>



    然后,我們配置JmsTemplate組件。我們?cè)跇颖緫?yīng)用中使用JmsTemplate102。使用defaultDestination屬性來(lái)指定JMS destination。

    清單6,JMS template配置

    <bean id="jmsTemplate" 
    ??????class="org.springframework.jms.core.JmsTemplate102">
    ????<property name="connectionFactory">
    ????????<ref bean="jmsQueueConnectionFactory"/>
    ????</property>
    ????<property name="defaultDestination">
    ????????<ref bean="destination"/>
    ????</property>
    ????<property name="receiveTimeout">
    ????????<value>30000</value>
    ????</property>
    </bean>



    最后,我們配置發(fā)送和接收者組件。清單7和清單8顯示了Sender 和Receiver 對(duì)象配置。

    清單7,JMS Sender配置

    Listing 7. JMS Sender configuration
    <bean id="jmsSender" class="springexample.client.JMSSender">
    ????<property name="jmsTemplate">
    ????????<ref bean="jmsTemplate"/>
    ????</property>
    </bean>



    清單8,JMS Receiver配置

    <bean id="jmsReceiver" class="springexample.client.JMSReceiver">
    ????<property name="jmsTemplate">
    ????????<ref bean="jmsTemplate"/>
    ????</property>
    </bean>



    測(cè)試和監(jiān)控

    我些了一個(gè)叫做LoanApplicationControllerTest的測(cè)試類來(lái)測(cè)試LoanProc應(yīng)用。我們使用這個(gè)類來(lái)設(shè)置貸款參數(shù)和調(diào)用那個(gè)信用請(qǐng)求服務(wù)類。

    讓我們看看使用傳統(tǒng)JMS而不用Spring JMS API的消息發(fā)送者實(shí)現(xiàn)。清單9顯示了MessageSenderJMS這個(gè)類的sendMessage方法,這個(gè)類具備使用JMS API處理消息的所有必須步驟。

    清單9,傳統(tǒng)JMS實(shí)現(xiàn)

    public void sendMessage() {

    ????queueName = "queue/CreditRequestSendQueue";
    ????System.out.println("Queue name is " + queueName);

    ????/*
    ???? * Create JNDI Initial Context
    ???? */
    ????try {
    ????????Hashtable env = new Hashtable();
    ????????env.put("java.naming.factory.initial",
    ????????????"org.jnp.interfaces.NamingContextFactory");
    ????????env.put("java.naming.provider.url","localhost");
    ????????env.put("java.naming.factory.url.pkgs",
    ????????????"org.jnp.interfaces:org.jboss.naming");

    ????????jndiContext = new InitialContext(env);
    ????} catch (NamingException e) {
    ????????System.out.println("Could not create JNDI API " +
    ????????????"context: " + e.toString());
    ????}

    ????/*
    ???? * Get queue connection factory and queue objects from JNDI context.
    ???? */
    ????try {
    ????????queueConnectionFactory = (QueueConnectionFactory)
    ????????jndiContext.lookup("UIL2ConnectionFactory");

    ????????queue = (Queue) jndiContext.lookup(queueName);
    ????} catch (NamingException e) {
    ????????System.out.println("JNDI API lookup failed: " +
    ????????????e.toString());
    ????}

    ????/*
    ???? * Create connection, session, sender objects.
    ???? * Send the message.
    ???? * Cleanup JMS connection.
    ???? */
    ????try {
    ????????queueConnection =
    ????????????queueConnectionFactory.createQueueConnection();
    ????????queueSession = queueConnection.createQueueSession(false,
    ????????????????Session.AUTO_ACKNOWLEDGE);
    ????????queueSender = queueSession.createSender(queue);
    ????????message = queueSession.createTextMessage();
    ????????message.setText("This is a sample JMS message.");
    ????????System.out.println("Sending message: " + message.getText());
    ????????queueSender.send(message);

    ????} catch (JMSException e) {
    ????????System.out.println("Exception occurred: " + e.toString());
    ????} finally {
    ????????if (queueConnection != null) {
    ????????????try {
    ????????????????queueConnection.close();
    ????????????} catch (JMSException e) {}
    ????????}
    ????}
    }



    現(xiàn)在,讓我們看看用Spring實(shí)現(xiàn)的消息發(fā)送者。清單10顯示了MessageSenderSpringJMS類中send方法代碼。

    清單10,用Spring API 的JMS實(shí)現(xiàn)

    public void send() {
    ????try {
    ????????ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {
    ????????????????"spring-jms.xml"});

    ????????System.out.println("Classpath loaded");

    ????????JMSSender jmsSender = (JMSSender)appContext.getBean("jmsSender");

    ????????jmsSender.sendMesage();

    ????????System.out.println("Message sent using Spring JMS.");
    ????} catch(Exception e) {
    ????????e.printStackTrace();
    ????}
    }



    如你所見(jiàn),所有與管理JMS資源相關(guān)的資源步驟都由Spring容器用配置文件處理。我們僅需要獲取JMSSender引用并且調(diào)用它上面的sendMessage即可。

    結(jié)論

    本文中,我們看到Spring框架如何簡(jiǎn)化了使用JMS API的異步消息應(yīng)用開(kāi)發(fā)的工作。Spring移走了所有JMS消息處理必須的樣板代碼,如獲取連接工廠,從Java代碼創(chuàng)建隊(duì)列和會(huì)話對(duì)象并在運(yùn)行時(shí)用配置文件裝配它們。由于這個(gè)強(qiáng)大的IOC原理,我們可以不必修改Java代碼便可動(dòng)態(tài)交換JMS資源對(duì)象。

    因?yàn)楫惒较⑹菢?gòu)成SOA框架整體所需的一部分,Spring非常適合放入SOA工具集。同樣,JMS管理工具如Hermes使得創(chuàng)建,管理和控制JMS資源變得簡(jiǎn)單,尤其對(duì)系統(tǒng)管理員。

    資源
    本文樣本代碼
    Matrix:http://www.matrix.org.cn/
    Spring JMS documentation
    "1-2-3 Messaging with Spring JMS"
    JBoss MQ wiki

    Srini Penchikala是Flagstar Bank信息系統(tǒng)領(lǐng)域問(wèn)題專家。


    posted on 2006-09-13 17:06 xiaofeng 閱讀(223) 評(píng)論(0)  編輯  收藏 所屬分類: Spring


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    收藏夾

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 黄色免费在线观看网址| 中文字幕在线免费观看| 亚洲AV一宅男色影视| 亚洲精品免费网站| 九一在线完整视频免费观看| 亚洲色偷拍另类无码专区| 性xxxxx免费视频播放| 无码 免费 国产在线观看91| 久久国产精品一区免费下载| 亚洲娇小性xxxx| 亚洲中文字幕无码永久在线| 美女视频黄免费亚洲| 国产精品1024在线永久免费 | 中文字幕高清免费不卡视频| 亚洲人6666成人观看| 亚洲综合色区在线观看| 欧亚精品一区三区免费| 日韩电影免费在线观看网站| 亚洲AV无码专区国产乱码不卡| 亚洲国产精彩中文乱码AV| 麻豆国产精品入口免费观看| 人人玩人人添人人澡免费| 亚洲Aⅴ在线无码播放毛片一线天| 久久久无码精品亚洲日韩按摩| 免费中文字幕在线| 国色精品卡一卡2卡3卡4卡免费| 中文字幕视频免费在线观看| 亚洲暴爽av人人爽日日碰| 亚洲白嫩在线观看| 亚洲人成人无码网www电影首页| 麻豆国产精品入口免费观看| 青娱乐免费视频在线观看| 国内精品一级毛片免费看| 美女被暴羞羞免费视频| 亚洲第一男人天堂| 亚洲图片中文字幕| 亚洲一区二区三区高清| 亚洲精品白浆高清久久久久久| 国产乱子伦精品免费女| 成人超污免费网站在线看| 特黄特色大片免费|