基於Spring架構的WebSphere應用開發

來源:互聯網
上載者:User
web   概

  輕量級的公司專屬應用程式開發越來越受到廣大J2EE應用開發人員的追捧,而Spring架構又是輕量級容器的傑出代表。由於Spring的使用日漸廣泛,因此已有許多基於WebSphere應用伺服器(WAS)的應用採用了Spring架構。本文首先介紹使用Spring開發Web應用的基本問題,然後結合WebSphere應用伺服器,講述Spring應用如何結合容器提供的服務。文章目的是與大家一起探討如何更好的採用Spring架構開發基於WebSphere應用伺服器的應用。

   1、Spring架構的主要思想描述

  Spring架構的核心思想我們可以用兩個字來描述,那就是"解耦"。應用程式的各個部分之間(包括代碼內部和代碼與平台之間)盡量形成一種松耦合的結構,使得應用程式有更多的靈活性。應用內部的解耦主要通過一種稱為控制反轉(IOC)的技術來實現。控制反轉的基本思想就是本來由應用程式本身來主動控制的調用等邏輯轉變成由外部設定檔來被動控制。通常我們用一個所謂的好萊塢原則(Don't call me. I will call you.)來比喻這種控制反轉的關係。由於控制反轉的概念相對比較廣泛,很多應用伺服器實際上也實現了不同程度的控制反轉技術,只是這些應用伺服器對應用程式的侵入性太強。因此Martin Fowler專門寫了一篇文章討論控制反轉這個概念,並提出一個描述更為準確的概念,叫依賴注入(Dependency Injection)。

  Spring架構中的各個部分都充分使用了這種依賴注入的技術實現,從而給應用以最大的靈活度。實際上,這種依賴注入的參數化應用控制並不是Spring的首創,比如IBM的多渠道應用整合平台(Branch Transformation Toolkit,BTT)很早就採用了這種外部參數化控制的技術。BTT中的"對象工廠"與Spring架構中的BeanFactory也有著異曲同工之妙。

  Spring架構另外一個比較重要的技術是它對於面向切面的編程(AOP)的支援。隨著應用複雜度的逐漸上升和對應用靈活性要求的提高,IT邏輯和商務邏輯盡量分離的呼聲也越來越高。AOP技術作為實現這種分離的一種比較好的途徑而越來越受到大家的重視。Spring提供的是一種動態AOP實現,也即通過代理模式動態地在目標對象的方法前後插入相應的處理代碼。應用程式與底層應用伺服器平台的解耦也可以藉助AOP技術來實現。Spring內建的AOP支援是一種錦上添花的功能。它使得一些本來必須由容器支援的功能,比如事務控制可以脫離開容器運行,從而達到"瘦身"的目的。這也是為什麼Spring架構常被人成為輕量級容器的一個原因。

Spring架構可以與許多已有的架構技術結合使用。J2EE技術應用的一個重要特點是相關的開源社區非常活躍。Web應用的不同層次都有非常多優秀的開源架構存在。比如Web層的Struts,OR映射層的Hibernate等。Spring架構並不重新發明輪子,它的出現不是為了替代這些已有的架構。相反,Spring架構在設計上可以獨立構建應用或者結合已有的架構一起構建應用。另外一個值得指出的地方是Spring架構的幾大模組之間相互耦合度很小,因此Spring架構的使用可以根據實際需要選其部分模組循序漸進的使用,而非必須統統照搬。

   2、基於Spring的Web應用基礎

  2.1 Web應用的典型層次

  Web應用一般在邏輯上根據功能分為以下幾層:

  1.展示層

  這一層主要如何產生展示給終端使用者的介面,儘可能少的包含商務邏輯處理。對於基於J2EE的Web應用,JSP是其最為常見的一種技術。Spring對於展示層的支援非常靈活,除了直接支援JSP之外,它還支援基於FreeMarker模板,基於Velocity模板或其它文件類型的介面等的表現層實現。

  2.業務層

  業務層一般包含主要的商務邏輯,尤其是與用例相對應的那些商務邏輯。另外,這一層也適合包含交易管理和安全控制方面的邏輯。良好的業務層設計可以使得展示層可以採用不同的技術而不影響業務層。業務層的功能上可以類比於J2EE技術中的無狀態會話BEAN層次。

  3.Data Access Objects(DAO)介面層

  DAO實際上就是資料介面層,在應用中建議通過介面來體現。DAO的存在使得資料訪問可以與底層持久化層的具體實現相分離。一般在DAO介面中主要就是實現資料對象的查詢、儲存、刪除等操作。從理論上講,DAO層與底層資料的儲存方式是獨立的,也就是說並不一定要求是關係型資料庫。Spring架構在設計的時候也考慮到了其它非關係型資料庫資料來源的情況。

  4.持久業務對象

  持久業務對象是問題域中業務對象的持久化表示,比如一個使用者物件,一個銀行帳戶等。我們一般通過某種O/R映射技術來實現這些業務對象的持久化。持久業務對象是可以包含商務邏輯的,與業務層所包含的商務邏輯不同的地方是持久業務對象所包含的是與具體業務對象直接相關且更為通用的商務邏輯。

  5.公司資訊系統

  公司資訊系統泛指Web應用需要串連的後台系統,一般可以分為三大類,即ERP系統,企業傳統的遺留系統和關係型資料庫。大部分Web應用都是基於關係型資料庫的,這也是像Spring等常見架構所主要考慮的公司資訊系統。

  設計良好的Web應用在層次一般是上一層依賴下一層,但是下一層不依賴上一層。我們可以暫時概括為"向下而不向上依賴原則"。為了使得不同層次之間的依賴降到最低,建議使用介面耦合。這一點又是Spring架構發揮它外部配置優勢的地方。

  2.2 MVC的選擇

  雖然說MVC這種模式早在Java語言出現前就有了,但是這種模式在J2EE時代才大行其道,為廣大Web應用開發人員所接受。對於各種基於MVC的架構而言,其要解決的問題主要可以分為以下幾部分:

  1.將Web頁面中的輸入封裝成一個資料對象,比如像Struts的表單BEAN,Spring MVC中的命令類等。

  2.根據請求的不同,由負責分發的控制器來映射和調用相應的邏輯處理單元,並將上面的資料對象作為參數傳入。

  3.邏輯處理單元完成相應的處理之後又把結果放入一個資料對象。

  4.在選擇的展現介面中把返回的資料對象通過某種方式顯示出來。

  在使用Spring構建MVC的時候,可以選擇直接使用Spring自己的MVC實現,或者利用Spring對已有的一些MVC架構的支援。比如Spring可以支援Struts,WebWork等,與它們結合使用。Spring引以為傲的非侵入的特性在Spring MVC上表現得並不如人意。它與Servlet API的耦合度較其它部分高,而且需要使用一些Spring的介面和類。

  Spring MVC的主要分發器實現是org.springframework.web.servlet.DispatcherServlet,這是Spring MVC的訪問入口。Spring提供SimpleFormController,AbstractCommandController等類來協助應用構建各種控制器動作,並用ModelAndView類來聯絡展示和邏輯返回資料。如上節所述,Spring MVC能夠支援不同的介面展示技術,而且介面的展示和其後面控制器的實現是分離的,也即介面展示技術的變化不用修改控制器的實現,只需要利用Spring的控制反轉技術修改外部設定檔即可。比如,在使用JSP展示技術時,外部設定檔的viewResolver定義如下:

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix"><value>/view/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
  如果切換到FreeMaker模板技術,那麼除了頁面模板的修改之外,主要就是把對應的外部設定檔更改一下即可,如下所示。具體的展示邏輯部分不用做什麼修改。

<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.freemarker.FreeMarkerView
</value>
</property>
<property name="suffix"><value>.ftl</value></property>
</bean>
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath">
<value>/view/</value>
</property>
</bean>


  如果不使用Spring的MVC架構而想結合已有的一些MVC架構,Spring也是支援的。Spring對於常見的MVC架構都提供了支援,包括Struts,WebWork,Tapestry和JSF等。結合使用這些架構的一個好處是可以使用一些已有的熟悉的技術,另外結合Spring的AOP攔截器可以相對比較容易地處理架構動作共有的事情,比如動作的Tlog等。如果選擇這些MVC架構,那麼在使用架構的設定檔和應用的Spring設定檔都需要做相應的修改。比如使用Struts的時候,Struts-config.xml設定檔中的映射動作類型一般會設定成org.springframework.web.struts.DelegatingActionProxy,或者設定控制器為org.springframework.web.struts.DelegatingRequestProcessor。然後需要在相應應的WebApplicationContext中定義與Struts Action對應的Bean。這樣就可以充分利用Spring的控制反轉技術來管理Struts的Action了。

  另外在使用這些架構的時候要解決的一個問題是內容相關的裝載。比如使用Struts,可以使用ContextLoaderPlugin來裝載Web上下文。這個ContextLoaderPlugin替換了原來通過DispacherServlet裝載的方式。需要在struts-config.xml檔案中添加如下條目:<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/>。這種方式可以使Spring的Web上下文隨著Struts ActionServlet的初始化而裝載。

  因此,如果使用者已有的應用是基於某個MVC架構,或者使用者熟悉某個架構,那麼可以利用Spring對這些架構的支援結合使用。因為我們的目的本來就是為瞭解決問題而不是為了使用某種技術。但是對其它使用者而言,如果不是對已有的一些MVC架構比較熟悉的話,那就直接使用Spring的MVC架構就可以了。

  2.3 Web Context設定

  對於不依賴於應用伺服器的Spring 上下文(Context)設定,通常在應用代碼中通過FileSystemXmlApplicationContext或ClasspathXmlApplicationContext來擷取。比如使用這樣的代碼來得到上下文:

ApplicationContext ctx = new FileSystemXmlApplicationContext("config.xml");
  但是按照控制反轉的原則,應用程式代碼應該儘可能少的知道內容相關的設定。因此,在基於Spring的Web應用中,這樣的代碼也可以省去。Spring可以通過配置讓Web容器自動裝載上下文設定檔。從本質上講,Web應用的ServletContext就是Spring用來存放應用內容相關的地方。Spring中與Web Context裝載相關的有幾個類:

  1.ContextLoaderListener:一般的應用伺服器如WAS都能先裝載Listener,如果不是的話,那麼只能使用ContextLoaderServlet。

  2.ContextLoaderServlet:需要配置<load-on-startup>使得它率先裝載。真正裝載Context的類是ContextLoader,上面兩個類只是兩種調用ContextLoader的不同途徑。ContextLoader內部實際調用的是XmlWebApplicationContext,其預設設定檔為/WEB-INF/applicationContext.xml。

  如果使用ContextLoaderListener,其在web.xml中的配置一般如下:

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
  如果使用ContextLoaderServlet,其在web.xml中的配置一般如下:

<servlet>
<servlet-name>context</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
  應用本身可能除了基於HTTP的Web渠道之外還通過別的渠道對外提供服務,因此,一個比較好的做法是把展示相關的配置與後面業務處理部分的配置分開。這樣如果更改了應用的訪問渠道,只需要修改對應的設定檔即可。因此,Spring提供了一個WebApplicationContext的概念。在WebApplicationContext中一般包含與Web訪問相關的配置定義,包括各種控制動作的定義、介面展示的定義等等。

  WebApplicationContext一般由DispatcherServlet來初始化。在上下文階層上可以把它看成是ApplcationContext的子上下文。在預設的情況下,DispatcherServlet裝載的設定檔名稱為其Servlet名稱-Servlet.xml,但是可以通過contextConfigLocation參數來定製。DispatcherServlet在web.xml中的定義樣本如下:

<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context/Webcontrollers.xml</param-value>
</init-param>
  2.4 資料持久化層

  雖然使用J2EE技術的Web應用可以串連多種不同的公司資訊系統(EIS),但是毫無疑問資料庫是其中最為重要和常見的一種。正因如此,Spring對資料庫訪問提供了非常完備的支援。Data Access Objects(DAO)模式是J2EE模式中非常重要的一種。它的主要目的是使得持久化層與商務邏輯層分離,從而屏蔽持久化層的具體實現。我們可以把Spring的DAO支援分為兩大類,一是直接基於Spring JDBC模板的資料訪問,另一類是基於某種O/R映射架構的資料訪問。這裡剛好可以使用Spring的控制反轉特性,通過外部設定檔來定義DAO介面和實際實作類別之間的關係。Spring架構目前支援的O/R映射架構套件括Hibernate、JDO、TopLink、iBATIS等。

  假設我們定義了一個userDAO。當使用JDBC來實現這個DAO的時候,定義的類可以如下所示:

public class userDAOJDBC extends JdbcDaoSupport implements userDAO{ … }
  如果使用Hibernate來實現這個DAO的時候,定義的類如下:

public class UserDAOHibernate extends HibernateDaoSupport implements UserDAO { … }
  Spring對於其它的O/R映射機制都有相應的抽象類別供應用使用,比如對於iBATIS有SqlMapClientDaoSupport,對於JDO有JdoDaoSupport等。

  下面我們看一下如何在Spring的設定檔中定義上述DAO與具體實現的關係。假設我們的userDAO具體實現是通過Hibernate,那麼在applicationContext.xml中的一個DAO可以定義如下:

<bean id="userDAO" class="com.fgw.dao.hibernate.UserDAOHibernate">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
  在這裡我們實際DAO介面定義是:com.fgw.dao.UserDAO,而具體實作類別為:com.fgw.dao.hibernate.UserDAOHibernate。顯然,對於其它DAO的實現,我們只需要在設定檔中修改相應的實作類別(具體實作類別當然是比不可少的)和屬性即可。比如對於JDBC的DAO實現,屬性就定義成相應的資料來源。

  3、Spring與WebSphere應用伺服器的配合

  Spring與底層J2EE應用伺服器還是存在一些需要結合的地方,這裡給出WAS中的一些結合點。

  3.1 使用WAS資料來源

  在Java應用程式中,資料庫的串連一般有兩種方式來得到。一種是通過java.sql.DriverManager的方式來得到資料庫連接。這種方式不依賴於應用服務的支援,但是也不提供資料庫連接池的功能。另外一種方式是通過javax.sql.DataSource的方式來得到資料庫連接。在傳統基於J2EE的應用需要通過JNDI來得到資料來源(javax.sql.DataSource)對象,然後再通過資料來源來得到相應的資料庫連接。常見的應用伺服器都支援這種方式,且一般都提供了資料庫連接池的支援。雖然說我們一般推薦使用資料庫連接池,但是也有一些時候我們需要脫離開應用伺服器的環境使用資料庫(比如單元測試,比如應用移植等)。然而應用程式使用這兩種方式的時候代碼是不一樣的,因此只能通過代碼來應變。Spring提供了一個統一使用資料來源的解決方案,然後通過控制反轉的機制用外部設定檔來指定使用的資料來源。這樣一方面可以統一這兩種得到資料庫連接的方式,另一方面也不需要像通常的J2EE應用通過繁瑣的JNDI代碼來得到資料來源。這樣應用程式也就不需要知道使用的何種資料來源。

  Spring提供了一個DriverManagerDataSource類來統一第一種方式的資料來源擷取。如果使用WAS中的Cloudscape資料庫,用外部設定檔可配置如下:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.ibm.db2j.jdbc.DB2jDriver</value>
</property>
<property name="url">
<value>jdbc:db2j:D:\\DBName</value>
</property>
</bean>
  Spring提供了JndiObjectFactoryBean類來支援第二種方式的資料來源擷取。假設WAS中已經配置好的資料來源名稱為jdbc /MyDB,那麼用外部設定檔可配置如下:

<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/jdbc/MyDB</value></property>
</bean>
或者
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>jdbc/MyDB</value></property>
<property name="resourceRef"><value>true</value></property>
</bean>
  從上面配置我們可以得知,通過使用Spring,應用程式能夠統一使用不同的資料來源實現。如果使用環境發生變化,那麼只需要修改Spring的設定檔即可。對於部署在WAS上的Web應用,在生產環境中推薦使用WAS實現的資料庫連接池。一方面是因為串連池實現地比較完善。另一方面,使用WAS提供的資料庫連接池可以很完善地支援JTA事務。

  3.2 使用WAS的JTA

  Web應用程式在使用事務的時候常常會涉及一個事務類型的選擇。是選擇像JDBC事務這樣的本地事務呢還是使用JTA支援的全域事務。這個與應用程式需要涉及到的交易管理員類型和個數密切相關。Spring本身不支援分散式交易,因此分散式交易需要底層的JTA。但是Spring提供了事務的抽象,即底層真正事務實現可以切換而不影響應用程式代碼。這樣應用程式可以依賴於底層WAS,也可以輕易地脫離開應用伺服器的環境。這一點與前面資料來源的抽象非常類似。

  WAS本身對於事務劃分有兩種支援方式,一種是聲明式的,當然這種管理方式需要EJB容器的支援,即所謂的容器管理事務(CMT)。另外一種方式是編程式的,通過程式碼來直接使用JTA編程介面。Spring對於事務的劃分也可以分為聲明式和編程式兩種方式。對於Spring編程式的事務劃分方式,總體上可以分為兩大類。一類是通過直接使用實現PlatformTransactionManager介面的類。另一類是通過使用TransactionTemplate模板類,模板類的使用可以簡化事務控制碼。Spring對於聲明式事務劃分的支援實際上是利用了它的AOP機制。相對於編程式事務劃分,這種基於AOP的方式比較靈活,而且對代碼的侵入性幾乎為零。因此,如果沒有特殊需要推薦使用這種事務劃分方式。基於AOP的常用事務劃分方式可以使用ProxyFactoryBean加TransactionInterceptor方式,或者使用TransactionPorxyFactoryBean的方式。前一種方式相對比較靈活,而後一種則對使用相對比較簡單。

  無論是哪一種事務劃分方式,底層都需要一個交易管理機製作為支撐。如果是單一的事務資源管理員,那麼根據所使用的後台交易管理資源不同的類型,可以選擇的PlatformTransactionManager實現有DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager, PersistenceBrokerTransactionManager,和JmsTransactionManager等。無論是單個還是多個事務資源管理員,都可以使用JtaTransactionManager類。如果使用JtaTransactionManager,那麼所有交易管理實際都會委託給底層應用伺服器的JTA實現。

  例如,如果使用JDBC或iBATIS,那麼我們可以使用簡單的DataSourceTransactionManager,外部設定檔片斷如下:

<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
  如果使用Hibernate,那麼我們可以使用HibernateTransactionManager,外部設定檔片斷如下:

<bean id="transactionManager" class="org.springframework.orm.hibernate.
HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
  使用WAS的JTA支援,我們只需要把上述對應bean中的class屬性改成class屬性改為org.springframework.transaction.jta.JtaTransactionManager,然後再把屬性改為WebSphere對應的TransactionManager,參考如下:

<bean id="wasTxMgr"
class="org.springframework.transaction.jta.WebSphereTransactionManagerFactoryBean"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref local="wasTxMgr"/>
</property>
</bean>
  通過採用Spring的事務支援,底層事務採用何種方式的決定就不必在一開始開發就做出決定。因為我們能夠通過Spring的外部設定檔來進行切換真正的事務支援。不過,雖然也有第三方的JTA支援,但是WAS能夠提供非常穩定的XA支援,因此推薦使用WAS的JTA,尤其是當應用涉及到分布交易處理的時候。這樣無論應用涉及幾個事務資源都可以統一解決。

  3.3 如何載入Spring的JAR包

  Spring架構的核心JAR包是spring.jar,但是根據實際使用方式需要一些擴充JAR包和依賴JAR包。那在WAS中如何處理這些JAR包檔案呢?在Web應用中一個簡單而直接的處理方式放是把這些使用到的JAR檔案都拷貝到對應的WEB-INF/lib目錄下面。這種方法雖然簡單,但是當有多個Spring應用程式的時候這種處理方式就需要在每個應用的WEB-INF/lib目錄下都拷貝一份相同的JAR檔案。這裡可以通過共用庫的方式來統一解決類程式庫共用這個問題。

  共用庫就是WAS專門用來解決不同應用程式之間共用JAR或本地庫檔案的一種機制。共用庫由一個名字、一個JAVA類路徑和/或一個裝載JNI庫本地庫路徑組成。它可以分別在單元,節點和伺服器層級定義。但是共用庫定義了並不意味著它會被裝載,只有當這個共用庫與某個應用程式或應用伺服器關聯之後,它才會被載入。如果一個共用庫與一個應用程式關聯,那麼這個共用庫由應用程式類載入器載入。如果一個共用庫與應用伺服器關聯,那麼這個共用庫就需要一個專門定義的類載入器來載入。這個類載入器需要使用者自己定義。其操作如下:選應用伺服器比如server1'類載入器'建立一個類載入器'載入器與共用庫關聯。

  在建立這個類載入器之前一般都需要預先定義好共用庫。 根據上面的介紹可知,通過共用庫解決Spring應用的JAR套件共用問題,主要就是兩個步驟。一是,把Spring應用中需要共用的JAR包定義成為一個共用庫。二是,選定相應的WAS伺服器執行個體,把它與上面建立的共用庫關聯起來。這樣此WAS伺服器執行個體上的所有應用都能夠使用共用庫中定義的JAR包。使用共用庫這種方式的時候要注意理解類的裝載次序和方式。如果是這種與WAS伺服器執行個體關聯的共用庫JAR包,其類載入器在階層上在應用程式類載入器上面,即是它的父載入器。關於WAS的類裝載器結構和策略可以進一步參考WAS資訊中心。

  4、結束語

  Spring架構的核心內容並不依賴於任何容器,但是顯然基於Web的應用是Spring主要的應用類型。瞭解和使用Spring架構一方面可以簡化應用的開發與測試,另一方也可以加深對J2EE技術的理解。另外輕量級的Web應用開發正在成為一種趨勢,因此何樂而不為之。上面所討論的只是Spring使用中常見的一些內容,Spring架構自己也正變得越來越複雜。當然,Spring、Hibernate等架構中體現的一些思想也正被JEE 5規範所借鑒,尤其是EJB 3中也有了控制反轉的應用和POJO的大量使用。實際上無論是JEE技術標準還是Spring等架構,其目的都是如何簡化公司專屬應用程式的開發,只是作為標準,JEE要考慮的內容更為廣泛一些,程度也更為深入一些。

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。