乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Spring框架簡(jiǎn)介

       某某某1014 2014-07-27

      原文地址:  http://my.oschina.net/myriads/blog/37922

      1、使用框架的意義與Spring的主要內(nèi)容

           隨著軟件結(jié)構(gòu)的日益龐大,軟件模塊化趨勢(shì)出現(xiàn),軟件開(kāi)發(fā)也需要多人合作,隨即分工出現(xiàn)。如何劃分模塊,如何定義接口方便分工成為軟件工程設(shè)計(jì)中越來(lái)越關(guān)注的問(wèn)題。良好的模塊化具有以下優(yōu)勢(shì):可擴(kuò)展、易驗(yàn)證、易維護(hù)、易分工、易理解、代碼復(fù)用。

           優(yōu)良的模塊設(shè)計(jì)往往遵守“低耦合高內(nèi)聚”的原則。而“框架”是對(duì)開(kāi)發(fā)中良好設(shè)計(jì)的總結(jié),把設(shè)計(jì)中經(jīng)常使用的代碼獨(dú)立出來(lái),所形成的一種軟件工具。用戶遵守它的開(kāi)發(fā)規(guī)則,就可以實(shí)現(xiàn)良好的模塊化,避免軟件開(kāi)發(fā)中潛在的問(wèn)題。廣義上的框架無(wú)處不再,一個(gè)常見(jiàn)的例子就是PC硬件體系結(jié)構(gòu),人們只要按照各自需要的主板、顯卡、內(nèi)存等器件就可以任意組裝成自己想要的電腦。而做主板的廠商不用關(guān)心做顯卡廠商的怎么實(shí)現(xiàn)它的功能。軟件框架也是如此,開(kāi)發(fā)人員只要在Spring框架中填充自己的業(yè)務(wù)邏輯就能完成一個(gè)模塊劃分清晰紛的系統(tǒng)。

           這里主要通過(guò)一個(gè)銀行通知用戶月收支記錄的小例子來(lái)介紹輕型J2EE框架Spring的主要內(nèi)容、它所解決的問(wèn)題和實(shí)現(xiàn)的方法。

      Spring框架主要可以分為3個(gè)核心內(nèi)容:

              1、容器

              2、控制反轉(zhuǎn)(IoC ,Inversion of Control)

              3、面向切面編程(AOP ,Aspect-Oriented Programming)

            例子中依次對(duì)這些特性進(jìn)行介紹,描述了軟件模塊化后存在的依賴與問(wèn)題,以及Spring框架如何解決這些問(wèn)題。 

      2、一個(gè)簡(jiǎn)單的例子程序

           假設(shè)有一個(gè)如下應(yīng)用場(chǎng)景:(1)一個(gè)銀行在每月的月初都需要向客戶發(fā)送上個(gè)月的賬單,賬單發(fā)送的方式可以為紙質(zhì)郵寄、或者短信方式。(2)還有一個(gè)潛在的需求:為了安全起見(jiàn),在每個(gè)函數(shù)操作過(guò)程中都需要記錄日志,記錄參數(shù)傳入是否正常,函數(shù)是否正常結(jié)束,以便出錯(cuò)時(shí)系統(tǒng)管理員查賬。

           那么對(duì)這個(gè)需求進(jìn)行簡(jiǎn)單實(shí)現(xiàn)。系統(tǒng)框圖如下所示:

          首先定義一個(gè)賬單輸出的接口:

      1 //接口
      2 public interface ReportGenerator{
      3     publicvoid generate(String[][] table) ;
      4 }

           實(shí)現(xiàn)“打印紙質(zhì)賬單”與“發(fā)送短信”兩個(gè)具體功能:

      1 //賬單報(bào)表實(shí)現(xiàn)類 
      2 public class PageReportGenerator implement ReportGenerator {
      3     publicvoid generate(String[][] table) {
      4         log4j.info( ... );   //輸出日志 
      5         ...打印操作,以便工作人員郵遞給客戶
      6         log4j.info( ... );   //輸出日志 
      7     
      8 }
      1 //短信報(bào)表實(shí)現(xiàn)類 
      2 public class SMSReportGenerator implement ReportGenerator {
      3     publicvoid generate(String[][] table) {
      4         log4j.info( ... );
      5         ...短信發(fā)送操作
      6         log4j.info( ... );
      7      }
      8 }

          上層業(yè)務(wù)邏輯對(duì)上個(gè)月的賬目進(jìn)行統(tǒng)計(jì)并調(diào)用接口產(chǎn)生紙質(zhì)或者短信結(jié)果:

      01 //上層業(yè)務(wù)中的服務(wù)類 
      02 public class ReportService{ 
      03     privateReportGenerator reportGenerator = newSMSReportGenerator(); 
      04     publicvoid generateMonthlyReport(intyear, int month) { 
      05         log4j.info( ... ); 
      06         String[][] statistics =null
      07         ... 
      08         reportGenerator.generate(statistics); 
      09     }
      10
      這個(gè)實(shí)現(xiàn)源代碼請(qǐng)查看文章結(jié)尾附錄中的"BankOld"。源代碼中與例子中程序略有區(qū)別:由于使用log4j需要引用外部的包,并且需要寫配置文件,為了方便,源代碼中的日志輸出用system.out.println()代替。

      3、Spring中的容器

              A、模塊化后出現(xiàn)的問(wèn)題與隱患

              假設(shè)隨著工程的復(fù)雜化,上面的例子需要分成兩個(gè)模塊,以便開(kāi)發(fā)時(shí)分工,一般會(huì)以如下結(jié)構(gòu)劃分:

          劃分后再看原來(lái)的代碼: 

      1 //上層業(yè)務(wù)中的服務(wù)類 
      2 public class ReportService{ 
      3     privateReportGenerator reportGenerator = newSMSReportGenerator(); //隱患 
      4   
      5     publicvoid generateMonthlyReport(intyear, int month) { 
      6         ... 
      7     
      8 }

           在服務(wù)類有private ReportGenerator reportGenerator = new SMSReportGenerator();這么一行代碼,ReportService類與SMSReportGenerator類不屬于同一個(gè)模塊,當(dāng)開(kāi)發(fā)人員B對(duì)內(nèi)部實(shí)現(xiàn)進(jìn)行修改時(shí),由于存在依賴,開(kāi)發(fā)人員A也要進(jìn)行修改(比如之前喜歡短信收賬單的客戶感覺(jué)短信不夠詳細(xì),希望以后改用郵件收賬單,那么開(kāi)發(fā)人員B需要實(shí)現(xiàn)一個(gè)MailReportGenerator類,在開(kāi)發(fā)人員B修改代碼是,開(kāi)發(fā)人員A也需要改代碼------聲明部分修改)。如果系統(tǒng)龐大new
      SMSReportGenerator()大量使用的話,修改就會(huì)十分復(fù)雜,一個(gè)聲明沒(méi)有修改就會(huì)出現(xiàn)大的BUG。

          所以需要一種劃分,讓各個(gè)模塊盡可能獨(dú)立,當(dāng)開(kāi)發(fā)人員B修改自己的模塊時(shí),開(kāi)發(fā)人員A不需要修改任何代碼。

          B、問(wèn)題出現(xiàn)的原因

          為例子中的程序畫一個(gè)UML依賴圖:

          可以發(fā)現(xiàn)上述問(wèn)題出現(xiàn)的原因主要是:模塊A與模塊B不但存在接口依賴,還存在實(shí)現(xiàn)依賴。ReportGenerator每次修改它的實(shí)現(xiàn),都會(huì)對(duì)ReportService產(chǎn)生影響。那么需要重構(gòu)消除這種實(shí)現(xiàn)依賴。

          C、用容器解決問(wèn)題

          消除實(shí)現(xiàn)依賴一般可以通過(guò)添加一個(gè)容器類來(lái)解決。在例子程序容器代碼如下: 

      01 //容器類 
      02 public class Container { 
      03   
      04     publicstatic Container instance; 
      05   
      06     privateMap<String, Object> components; 
      07   
      08     publicContainer(){ 
      09         component =new HashMap<String, Object>(); 
      10         instance =this
      11   
      12         ReportGenertor reportGenertor =new SMSReportGenertor(); 
      13         components.put(“reportGenertor”, reportGenertor); 
      14   
      15         ReportService reportService =new ReportService(); 
      16         components.put(“reportService”, reportService); 
      17     
      18   
      19     publicObject getComponent(String id){ 
      20         returncomponents.get(id); 
      21     
      22 }

          使用容器后,模塊A的ReportService的屬性實(shí)現(xiàn)方法也發(fā)生了變化。

      01 //服務(wù)類變更,降低了耦合 
      02 public class ReportService{ 
      03   
      04     //private ReportGenerator reportGenerator = new SMSReportGenerator(); 
      05     privateReportGenerator reportGenerator = (ReportGenerator) Container.instance.getComponent(“reportGenerator”); 
      06   
      07     publicvoid generateMonthlyReport(intyear, int month) { 
      08         ... 
      09     
      10 }

           這樣的話,class都在容器中實(shí)現(xiàn),使用者只需要在容器中查找需要的實(shí)例,開(kāi)發(fā)人員修改模塊B后(在模塊中增加郵件報(bào)表生成類MailReportGenerator),只需要在容器類中修改聲明(把ReportGenertor
      reportGenertor = new SMSReportGenertor();改為ReportGenertor reportGenertor = new
      MailReportGenertor();)即可,模塊A不需要修改任何代碼。一定程度上降低了模塊之間的耦合。

      4、Spring中的控制反轉(zhuǎn)

       

          A、還存在的耦合

          使用容器后模塊A與模塊B之間的耦合減少了,但是通過(guò)UML依賴圖可以看出模塊A開(kāi)始依賴于容器類:

          之前的模塊A對(duì)模塊B的實(shí)現(xiàn)依賴通過(guò)容器進(jìn)行傳遞,在程序中用(ReportGenerator) Container.instance.getComponent(“reportGenerator”)的方法取得容器中SMSReportGenertor的實(shí)例,這種用字符(“reportGenerator”)指代具體實(shí)現(xiàn)類SMSReportGenertor 的方式并沒(méi)有完全的解決耦合。所以在銀行賬單的例子中我們需要消除ReportService對(duì)容器Container的依賴。

          B、控制反轉(zhuǎn)與依賴注入

          在我們常規(guī)的思維中,ReportService需要初始化它的屬性private ReportGenerator reportGenerator就必須進(jìn)行主動(dòng)搜索需要的外部資源。不使用容器時(shí),它需要找到SMSReportGenertor()的構(gòu)造函數(shù);當(dāng)使用容器時(shí)需要知道SMSReportGenertor實(shí)例在容器中的命名。無(wú)論怎么封裝,這種主動(dòng)查找外部資源的行為都必須知道如何獲得資源,也就是肯定存在一種或強(qiáng)或弱的依賴。那是否存在一種方式,讓ReportService不再主動(dòng)初始化reportGenerator,被動(dòng)的接受推送的資源?

          這種反轉(zhuǎn)資源獲取方向的思想被稱為控制反轉(zhuǎn)(IoC,Inversion of Control),使用控制反轉(zhuǎn)后,容器主動(dòng)地將資源推送給需要資源的類(或稱為bean)ReportService,而ReportService需要做的只是用一種合適的方式接受資源??刂品崔D(zhuǎn)的具體實(shí)現(xiàn)過(guò)程用到了依賴注入(DI,Dependecncy Injection)的設(shè)計(jì)模式,ReportService類接受資源的方式有多種,其中一種就是在類中定義一個(gè)setter方法,讓容器將匹配的資源注入:setter的寫法如下: 

      01 //為需要依賴注入的類加入一種被稱為setter的方法 
      02   
      03 public class ReportService{ 
      04   
      05     /*private ReportGenerator reportGenerator = 
      06         (ReportGenerator) Container.instance.getComponent(“reportGenerator”); */ 
      07   
      08     privateReportGenerator reportGenerator; 
      09   
      10     publicvoid setReportGenerator( ReportGenerator reportGenerator) { 
      11         this.reportGenerator = reportGenerator; 
      12     
      13   
      14     publicvoid generateMonthlyReport(intyear, int month) { 
      15         ...  
      16     
      17 }

          在容器中把依賴注入: 

      01 //容器類   
      02 public class Container { 
      03        
      04     ... 
      05     publicContainer ( ) { 
      06         component =new HashMap<String, Object>(); 
      07         instance =this
      08         ReportGenertor reportGenertor =new SMSReportGenertor(); 
      09         components.put(“reportGenertor”, reportGenertor); 
      10   
      11         ReportService reportService =new ReportService(); 
      12         reportService.setReportGenerator(reportGenerator);//使用ReportService的setter方法注入依賴關(guān)系 
      13         components.put(“reportService”, reportService);
      14     
      15     ... 
      16 }

          這樣一來(lái)ReportService就不用管SMSReportGenertor在容器中是什么名字,模塊A對(duì)于模塊B只有接口依賴,做到了松耦合。

          C、Spring IoC容器的XML配置

          每個(gè)使用Spring框架的工程都會(huì)用到容器與控制反轉(zhuǎn),為了代碼復(fù)用,Spring把通用的代碼獨(dú)立出來(lái)形成了自己的IoC容器供開(kāi)發(fā)者使用:

       

          與上面例子中實(shí)現(xiàn)的容器相比,Spring框架提供的IoC容器要遠(yuǎn)遠(yuǎn)復(fù)雜的多,但用戶不用關(guān)心Spring
      IoC容器的代碼實(shí)現(xiàn),Spring提供了一種簡(jiǎn)便的bean依賴關(guān)系配置方式------使用XML文件,在上面的例子中,配置依賴關(guān)系只要在工程根目錄下的“application.xml”編輯如下內(nèi)容:

      01 <?xmlversion="1.0"encoding="UTF-8"?> 
      02 <beans   xmlns="http://www./schema/beans"
      03     xmlns:xsi="http://www./2001/XMLSchema-instance"
      04     xmlns:p="http://www./schema/p"
      05     xsi:schemaLocation="http://www./schema/beans
      06          http://www./schema/beans/spring-beans-3.0.xsd" >
      07   
      08     <beanid="smsReportGenerator"class="bank.SMSReportGenerator"/>
      09   
      10     <beanid="reportService"class="bank.ReportService">  
      11        <propertyname="reportGenerator"ref="smsReportGenerator"/> 
      12     </bean>
      13  </beans>

              <?xml version="1.0" encoding="UTF-8"?>是標(biāo)準(zhǔn)的XML頭,xmlns引用的是一些命名空間,兩個(gè)一般在工程中自動(dòng)生成。后面的內(nèi)容由用戶輸入,主要表示實(shí)例化SMSReportGenerator,實(shí)例化ReportService并把SMSReportGenerator的對(duì)象smsReportGenerator賦值給ReportService的屬性reportGenerator,完成依賴注入。

      5、Spring中的面向切面編程

       

          A、日志問(wèn)題以及延伸

          在例子的需求中有一條是:需要記錄日志,以便出錯(cuò)時(shí)系統(tǒng)管理員查賬?;仡櫪又械拇a,在每個(gè)方法中都加了日志操作: 

      01 //服務(wù)類 
      02 public class ReportService{ 
      03     ... 
      04     publicvoid generateMonthlyReport(intyear, int month) { 
      05         log4j.info( ... );  //記錄函數(shù)的初始狀況參數(shù)等信息 
      06         String[ ][ ] statistics =null
      07         ... 
      08         reportGenerator.generate(statistics); 
      09         log4j.info( ... );  //記錄函數(shù)的執(zhí)行狀況與返回值 
      10     
      11 }
      01 //憑條報(bào)表實(shí)現(xiàn)類   
      02 public class PageReportGenerator implement ReportGenerator { 
      03   
      04     publicvoid generate(String[ ][ ] table) { 
      05   
      06         log4j.info( ... );      //記錄函數(shù)的初始狀況參數(shù)等信息 
      07         …打印操作 
      08         log4j.info( ... );      //記錄函數(shù)的執(zhí)行狀況與返回值 
      09     
      10 }

          可以看出在每個(gè)方法的開(kāi)始與結(jié)尾都調(diào)用了日志輸出,這種零散的日志操作存在著一些隱患,會(huì)導(dǎo)致維護(hù)的困難。比如日志輸出的格式發(fā)送了變化,那么無(wú)論模塊A還是模塊B的程序員都要對(duì)每個(gè)方法每個(gè)輸出逐條修改,極容易遺漏,造成日志輸出風(fēng)格的不一致。又比如不用Log4j日志輸出工具更換其他工具,如果遺漏一個(gè)將會(huì)出現(xiàn)嚴(yán)重BUG。

          與日志輸出相似的問(wèn)題在編程中經(jīng)常遇到,這種跨越好幾個(gè)模塊的功能和需求被稱為橫切關(guān)注點(diǎn),典型的有日志、驗(yàn)證、事務(wù)管理等。

          橫切關(guān)注點(diǎn)容易導(dǎo)致代碼混亂、代碼分散的問(wèn)題。而如何將很切關(guān)注點(diǎn)模塊化是本節(jié)的重點(diǎn)。
       
          B、代理模式

          傳統(tǒng)的面向?qū)ο蠓椒ê茈y實(shí)現(xiàn)很切關(guān)注點(diǎn)的模塊化。一般的實(shí)現(xiàn)方式是使用設(shè)計(jì)模式中的代理模式。代理模式的原理是使用一個(gè)代理將對(duì)象包裝起來(lái),這個(gè)代理對(duì)象就取代了原有對(duì)象,任何對(duì)原對(duì)象的調(diào)用都首先經(jīng)過(guò)代理,代理可以完成一些額外的任務(wù),所以代理模式能夠?qū)崿F(xiàn)橫切關(guān)注點(diǎn)。

          可能在有些程序中有很多橫切關(guān)注點(diǎn),那么只需要在代理外再加幾層代理即可。以銀行賬單為例介紹一個(gè)種用Java Reflection API動(dòng)態(tài)代理實(shí)現(xiàn)的橫切關(guān)注點(diǎn)模塊化方法。系統(tǒng)提供了一個(gè)InvocationHandler接口: 

      1 //系統(tǒng)提供的代理接口 
      2 public interface InvocationHandler { 
      3     publicObject invoke(Object proxy, Method method, Object[] args)throw Throwable; 
      4 }

          我們需要實(shí)現(xiàn)這個(gè)接口來(lái)創(chuàng)建一個(gè)日志代理,實(shí)現(xiàn)代碼如下:

      01 //日志代理實(shí)現(xiàn)   
      02 public class LogHandler implement InvocationHandler{ 
      03   
      04     privateObject target; 
      05   
      06     publicLogHandler(Object target){ 
      07         this.target = target; 
      08     
      09     publicObject invoke(Object proxy, Method method, Object[] args )throw Throwable{ 
      10   
      11         //記錄函數(shù)的初始狀況參數(shù)等信息 
      12         log4j.info(“開(kāi)始:方法”+ method.getName() + “參數(shù)”+Arrays.toString(args) );
      13    
      14   
      15         Object result = method.invoke(target, args); 
      16   
      17         //記錄函數(shù)的執(zhí)行狀況與返回值 
      18         log4j.info(“結(jié)束:方法”+ method.getName() + “返回值”+ result ); 
      19   
      20     }
      21  }

           這樣既可以使得日志操作不再零散分布于各個(gè)模塊,易于管理。調(diào)用者可以通過(guò)如下方式調(diào)用: 

      01 //主函數(shù)   
      02 public class Main{ 
      03     publicstatic void main(String[ ] args){ 
      04         ReportGenerator reportGeneratorImpl  =new SMSReportGenerator (); 
      05   
      06         //通過(guò)系統(tǒng)提供的Proxy.newProxyInstance創(chuàng)建動(dòng)態(tài)代理實(shí)例 
      07         ReportGenerator reportGenerator = (ReportGenerator ) Proxy.newProxyInstance(  
      08             reportGeneratorImpl.getClass().getClassLoader(), 
      09             reportGeneratorImpl.getClass().getInterfaces(), 
      10             newLogHandler(reportGeneratorImpl)
      11         ) ; 
      12         ...
      13     }
      14 }

          代理模式很好的實(shí)現(xiàn)了橫切關(guān)注點(diǎn)的模塊化,解決了代碼混亂代碼分散問(wèn)題,但是我們可以看出用 Java Reflection API 實(shí)現(xiàn)的動(dòng)態(tài)代理結(jié)構(gòu)十分復(fù)雜,不易理解,Spring框架利用了代理模式的思想,提出了一種基于JAVA注解(Annotation)和XML配置的面向切面編程方法(AOP ,Aspect-Oriented Programming)簡(jiǎn)化了編程過(guò)程。

          C、Spring AOP 使用方法

          Spring AOP使用中需要為橫切關(guān)注點(diǎn)(有些時(shí)候也叫切面)實(shí)現(xiàn)一個(gè)類,銀行賬單的例子中,切面的實(shí)現(xiàn)如下:

      01 //切面模塊實(shí)現(xiàn)   
      02 @Aspect    //注解1 
      03 public class LogAspect{ 
      04   
      05     @Before(“execution(* *.*(..))”)   //注解2 
      06     publicvoid LogBefore(JoinPoint joinPoint) throw Throwable{ 
      07         log4j.info(“開(kāi)始:方法”+ joinPoint.getSignature().getName() ); 
      08     
      09   
      10     @After(“execution(* *.*(..))”)    //注解3 
      11     publicvoid LogAfter(JoinPoint joinPoint) throw Throwable{ 
      12         log4j.info(“結(jié)束:方法”+ joinPoint.getSignature().getName() ); 
      13     }
      14 }

           注解1表示這個(gè)類是一個(gè)切面,注解2中" * *.*(..)* "是一個(gè)通配符,表示在容器中所有類里有參數(shù)的方法。@Before(“execution(* *.*(..))”)表示在所有類里有參數(shù)的方法前調(diào)用切面中德 LogBefore() 方法。同理,注解3中@After(“execution(* *.*(..))”)表示在所有類里有參數(shù)的方法執(zhí)行完后調(diào)用切面中的LogAfter()方法。
          實(shí)現(xiàn)完切面類后,還需要對(duì)Spring工程中的application.xml進(jìn)行配置以便實(shí)現(xiàn)完整的動(dòng)態(tài)代理: 

      01 <?xmlversion="1.0"encoding="UTF-8"?> 
      02 <beans   xmlns="http://www./schema/beans"
      03     xmlns:xsi="http://www./2001/XMLSchema-instance"
      04     xmlns:p="http://www./schema/p"
      05     xmlns:aop="http://www./schema/aop"    
      06     xsi:schemaLocation="http://www./schema/beans 
      07         http://www./schema/beans/spring-beans-3.0.xsd 
      08         http://www./schema/aop 
      09         http://www./schema/aop/spring-aop-3.0.xsd" > 
      10   
      11     <aop:aspectj-autoproxy/> 
      12     <beanid="smsReportGenerator"class="bank.SMSReportGenerator"/> 
      13     <beanid="reportService"class="bank.ReportService"
      14         <propertyname="reportGenerator"ref="smsReportGenerator"/> 
      15     </bean
      16     <beanclass="bank.LogAspect"/>
      17 </beans>

          這比之前IoC依賴關(guān)系配置的XML文件多了:xmlns:aop=http://www./schema/aop;http://www./schema/aop;http://www./schema/aop/spring-aop-3.0.xsd
      這3個(gè)主要是聲明XML中用于AOP的一些標(biāo)簽, <bean class="bank.LogAspect" /> 是在容器中聲明LogAspect切面,<aop:aspectj-autoproxy />用于自動(dòng)關(guān)聯(lián)很切關(guān)注點(diǎn)(LogAspect)與核心關(guān)注點(diǎn)(SMSReportGenerator,ReportService)。不難發(fā)現(xiàn)Spring AOP的方法實(shí)現(xiàn)橫切關(guān)注點(diǎn)得模塊化要比用Java Reflection API簡(jiǎn)單很多。

      6、Spring總結(jié)

       

               銀行月賬單報(bào)表例子通過(guò)使用Spring框架后變成了如下結(jié)構(gòu):

          在Spring框架的基礎(chǔ)上原來(lái)存在耦合的程序被分成松耦合的三個(gè)模塊。無(wú)論那個(gè)模塊修改,對(duì)其他模塊不需要額外改動(dòng)。這就完成了一種良好的架構(gòu),使軟件易理解,模塊分工明確,為軟件的擴(kuò)展、驗(yàn)證、維護(hù)、分工提供了良好基礎(chǔ)。這就是Spring框架作用。當(dāng)然Spring除了容器、控制反轉(zhuǎn)、面向切面之外還有許多其他功能,但都是在這三個(gè)核心基礎(chǔ)上實(shí)現(xiàn)的。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多