轉(zhuǎn)自: http://blog.csdn.net/a906998248/article/details/7514969
?
一、什么是 AOP。
AOP(Aspect Orient Programming),也就是面向切面編程 ??梢赃@樣理解, 面向?qū)ο缶幊蹋∣OP)是從靜態(tài)角度考慮程序結(jié)構(gòu),面向切面編程(AOP)是從動(dòng)態(tài)角度考慮程序運(yùn)行過程 。
?
二、AOP 的作用。
常常通過 AOP 來處理一些 具有橫切性質(zhì)的系統(tǒng)性服務(wù) ,如 事物管理、安全檢查、緩存、對(duì)象池管理 等,AOP 已經(jīng)成為一種非常常用的解決方案。
?
三、AOP 的實(shí)現(xiàn)原理。
如圖: AOP 實(shí)際上是由目標(biāo)類的代理類實(shí)現(xiàn)的 。 AOP 代理其實(shí)是由 AOP 框架動(dòng)態(tài)生成的一個(gè)對(duì)象,該對(duì)象可作為目標(biāo)對(duì)象使用 。A OP 代理包含了目標(biāo)對(duì)象的全部方法,但 AOP 代理中的方法與目標(biāo)對(duì)象的方法存在差異,AOP 方法在特定切入點(diǎn)添加了增強(qiáng)處理,并回調(diào)了目標(biāo)對(duì)象的方法 。
?
四、Spring 中對(duì) AOP 的支持
Spring 中 AOP 代理由 Spring 的 IoC 容器負(fù)責(zé)生成、管理,其依賴關(guān)系也由 IoC 容器負(fù)責(zé)管理 。因此,AOP 代理可以直接使用容器中的其他 Bean 實(shí)例作為目標(biāo),這種關(guān)系可由 IoC 容器的依賴注入提供。 Spring 默認(rèn)使用 Java 動(dòng)態(tài)代理來創(chuàng)建 AOP 代理 , 這樣就可以為任何接口實(shí)例創(chuàng)建代理了。當(dāng)需要代理的類不是代理接口的時(shí)候, Spring 自動(dòng)會(huì)切換為使用 CGLIB 代理,也可強(qiáng)制使用 CGLIB 。?
AOP 編程其實(shí)是很簡(jiǎn)單的事情。縱觀 AOP 編程, 其中需要程序員參與的只有三個(gè)部分:
?
- 定義普通業(yè)務(wù)組件。
- 定義切入點(diǎn),一個(gè)切入點(diǎn)可能橫切多個(gè)業(yè)務(wù)組件。
- 定義增強(qiáng)處理,增強(qiáng)處理就是在 AOP 框架為普通業(yè)務(wù)組件織入的處理動(dòng)作。
?
所以進(jìn)行 AOP 編程的關(guān)鍵就是定義切入點(diǎn)和定義增強(qiáng)處理。一旦定義了合適的切入點(diǎn)和增強(qiáng)處理,AOP 框架將會(huì)自動(dòng)生成 AOP 代理,即: 代理對(duì)象的方法 = 增強(qiáng)處理 + 被代理對(duì)象的方法 。
?
五、Spring 中 AOP 的實(shí)現(xiàn)。
Spring 有如下兩種選擇來定義切入點(diǎn)和增強(qiáng)處理。
?
- 基于 Annotation 的“零配置”方式:使用@Aspect、@Pointcut等 Annotation 來標(biāo)注切入點(diǎn)和增強(qiáng)處理。
- 基于 XML 配置文件的管理方式:使用 Spring 配置文件來定義切入點(diǎn)和增強(qiáng)點(diǎn)。
?
1、基于 Annotation 的“零配置”方式。
(1)、首先啟用 Spring 對(duì) @AspectJ 切面配置的支持。
?
- <?xml?version= "1.0" ?encoding= "UTF-8" ?>??
- <beans?xmlns= "http://www.springframework.org/schema/beans" ??
- ???????xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" ??
- ???????xmlns:aop= "http://www.springframework.org/schema/aop" ????????
- ???????xsi:schemaLocation="http: //www.springframework.org/schema/beans ??
- ???????????http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd ??
- ???????????http: //www.springframework.org/schema/aop ??
- ???????http: //www.springframework.org/schema/beans/spring-aop-3.0.xsd"> ??
- ????????<!--?啟動(dòng)對(duì) @AspectJ 注解的支持?-->??
- ????????<aop:aspectj-autoproxy/>??
- </beans>??
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/beans/spring-aop-3.0.xsd"> <!-- 啟動(dòng)對(duì)@AspectJ注解的支持 --> <aop:aspectj-autoproxy/> </beans>
如果不打算使用 Spring 的 XML Schema 配置方式,則應(yīng)該在 Spring 配置文件中增加如下片段來啟用@AspectJ 支持。
?
?
- <!--?啟用 @AspectJ ?支持?-->??
- <bean? class = "org.springframeword.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" ?/>??
<!-- 啟用@AspectJ 支持 --> <bean class="org.springframeword.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
?
?
(2)、定義切面 Bean。
當(dāng)啟動(dòng)了@AspectJ 支持后,只要在 Spring 容器中配置一個(gè)帶@Aspect 注釋的 Bean, Spring 將會(huì)自動(dòng)識(shí)別該 Bean 并作為切面處理。
?
- //?使用@Aspect?定義一個(gè)切面類 ??
- @Aspect ??
- public ? class ?LogAspect?{??
- ???????? //?定義該類的其他內(nèi)容 ??
- ????????...??
- }??
// 使用@Aspect 定義一個(gè)切面類 @Aspect public class LogAspect { // 定義該類的其他內(nèi)容 ... }
?
?
(3)、定義 Before 增強(qiáng)處理。
?
?
- //?定義一個(gè)切面 ??
- @Aspect ??
- public ? class ?BeforeAdviceTest?{??
- ???? //?匹配?com.wicresoft.app.service.impl?包下所有類的所有方法作為切入點(diǎn) ??
- ???? @Before ( "execution(*?com.wicresoft.app.service.impl.*.*(..))" )??
- ???? public ? void ?authorith(){??
- ????????System.out.println( "模擬進(jìn)行權(quán)限檢查。" );??
- ????}??
- }??
// 定義一個(gè)切面 @Aspect public class BeforeAdviceTest { // 匹配 com.wicresoft.app.service.impl 包下所有類的所有方法作為切入點(diǎn) @Before("execution(* com.wicresoft.app.service.impl.*.*(..))") public void authorith(){ System.out.println("模擬進(jìn)行權(quán)限檢查。"); } }
?
?
上面使用@Before Annotation 時(shí),直接指定了切入點(diǎn)表達(dá)式,指定匹配?
com.wicresoft.app.service.impl
包下所有類的所有方法執(zhí)行作為切入點(diǎn)。
關(guān)于這個(gè)表達(dá)式的規(guī)則如下圖。
?
(4)、定義 AfterReturning 增強(qiáng)處理。
?
- //?定義一個(gè)切面 ??
- @Aspect ??
- public ? class ?AfterReturningAdviceTest?{??
- ???? //?匹配?com.wicresoft.app.service.impl?包下所有類的所有方法作為切入點(diǎn) ??
- ???? @AfterReturning (returning= "rvt" ,?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" )??
- ???? public ? void ?log(Object?rvt)?{??
- ????????System.out.println( "模擬目標(biāo)方法返回值:" ?+?rvt);??
- ????????System.out.println( "模擬記錄日志功能..." );??
- ????}??
- }??
// 定義一個(gè)切面 @Aspect public class AfterReturningAdviceTest { // 匹配 com.wicresoft.app.service.impl 包下所有類的所有方法作為切入點(diǎn) @AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))") public void log(Object rvt) { System.out.println("模擬目標(biāo)方法返回值:" + rvt); System.out.println("模擬記錄日志功能..."); } }
?
?
(5)、定義 AfterThrowing 增強(qiáng)處理。
?
?
- //?定義一個(gè)切面 ??
- @Aspect ??
- public ? class ?AfterThrowingAdviceTest?{??
- ???? //?匹配?com.wicresoft.app.service.impl?包下所有類的所有方法作為切入點(diǎn) ??
- ???? @AfterThrowing (throwing= "ex" ,?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" )??
- ???? public ? void ?doRecoverActions(Throwable?ex)?{??
- ????????System.out.println( "目標(biāo)方法中拋出的異常:" ?+?ex);??
- ????????System.out.println( "模擬拋出異常后的增強(qiáng)處理..." );??
- ????}??
- }??
// 定義一個(gè)切面 @Aspect public class AfterThrowingAdviceTest { // 匹配 com.wicresoft.app.service.impl 包下所有類的所有方法作為切入點(diǎn) @AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))") public void doRecoverActions(Throwable ex) { System.out.println("目標(biāo)方法中拋出的異常:" + ex); System.out.println("模擬拋出異常后的增強(qiáng)處理..."); } }
?
?
(6)、定義 After 增強(qiáng)處理。
?
After 增強(qiáng)處理與AfterReturning?增強(qiáng)處理有點(diǎn)相似,但也有區(qū)別:
?
-
AfterReturning?增強(qiáng)處理處理只有在目標(biāo)方法成功完成后才會(huì)被織入。
- After 增強(qiáng)處理不管目標(biāo)方法如何結(jié)束(保存成功完成和遇到異常中止兩種情況),它都會(huì)被織入。
?
?
- //?定義一個(gè)切面 ??
- @Aspect ??
- public ? class ?AfterAdviceTest?{??
- ???? //?匹配?com.wicresoft.app.service.impl?包下所有類的所有方法作為切入點(diǎn) ??
- ???? @After ( "execution(*?com.wicresoft.app.service.impl.*.*(..))" )??
- ???? public ? void ?release()?{??
- ????????System.out.println( "模擬方法結(jié)束后的釋放資源..." );??
- ????}??
- }??
// 定義一個(gè)切面 @Aspect public class AfterAdviceTest { // 匹配 com.wicresoft.app.service.impl 包下所有類的所有方法作為切入點(diǎn) @After("execution(* com.wicresoft.app.service.impl.*.*(..))") public void release() { System.out.println("模擬方法結(jié)束后的釋放資源..."); } }
?
?
(7)、Around 增強(qiáng)處理
?
Around 增強(qiáng)處理近似等于 Before 增強(qiáng)處理和 ?AfterReturning 增強(qiáng)處理的總和。它可改變執(zhí)行目標(biāo)方法的參數(shù)值,也可改變目標(biāo)方法之后的返回值。
?
- //?定義一個(gè)切面 ??
- @Aspect ??
- public ? class ?AroundAdviceTest?{??
- ???? //?匹配?com.wicresoft.app.service.impl?包下所有類的所有方法作為切入點(diǎn) ??
- ???? @Around ( "execution(*?com.wicresoft.app.service.impl.*.*(..))" )??
- ???? public ?Object?processTx(ProceedingJoinPoint?jp)? throws ?java.lang.Throwable?{??
- ????????System.out.println( "執(zhí)行目標(biāo)方法之前,模擬開始事物..." );??
- ???????? //?執(zhí)行目標(biāo)方法,并保存目標(biāo)方法執(zhí)行后的返回值 ??
- ????????Object?rvt?=?jp.proceed( new ?String[]{ "被改變的參數(shù)" });??
- ????????System.out.println( "執(zhí)行目標(biāo)方法之前,模擬結(jié)束事物..." );??
- ???????? return ?rvt?+? "新增的內(nèi)容" ;??
- ????}??
- }??
// 定義一個(gè)切面 @Aspect public class AroundAdviceTest { // 匹配 com.wicresoft.app.service.impl 包下所有類的所有方法作為切入點(diǎn) @Around("execution(* com.wicresoft.app.service.impl.*.*(..))") public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable { System.out.println("執(zhí)行目標(biāo)方法之前,模擬開始事物..."); // 執(zhí)行目標(biāo)方法,并保存目標(biāo)方法執(zhí)行后的返回值 Object rvt = jp.proceed(new String[]{"被改變的參數(shù)"}); System.out.println("執(zhí)行目標(biāo)方法之前,模擬結(jié)束事物..."); return rvt + "新增的內(nèi)容"; } }
?
?
(8)、訪問目標(biāo)方法的參數(shù)。
?
訪問目標(biāo)方法最簡(jiǎn)單的做法是定義增強(qiáng)處理方法時(shí)將第一個(gè)參數(shù)定義為 JoinPoint 類型,當(dāng)該增強(qiáng)處理方法被調(diào)用時(shí),該 JoinPoint 參數(shù)就代表了織入增強(qiáng)處理的連接點(diǎn)。JoinPoint 里包含了如下幾個(gè)常用方法。
?
- Object[] getArgs(): 返回執(zhí)行目標(biāo)方法時(shí)的參數(shù)。
- Signature getSignature(): 返回被增強(qiáng)的方法的相關(guān)信息。
- Object getTarget(): 返回被織入增強(qiáng)處理的目標(biāo)對(duì)象。
- Object getThis(): 返回 AOP 框架為目標(biāo)對(duì)象生成的代理對(duì)象。
?
提示 : 當(dāng)時(shí)使用 Around 處理時(shí),我們需要將第一個(gè)參數(shù)定義為 ProceedingJoinPoint 類型,該類型是 JoinPoint 類型的子類 。
?
(9)、定義切入點(diǎn)。
所謂切入點(diǎn),其實(shí)質(zhì)就是為一個(gè)切入點(diǎn)表達(dá)式起一個(gè)名稱,從而允許在多個(gè)增強(qiáng)處理中重用該名稱。
Spring 切入點(diǎn)定義包含兩個(gè)部分:
?
- 一個(gè)切入點(diǎn)表達(dá)式。
- 一個(gè)包含名字和任意參數(shù)的方法簽名。
?
?
- //?使用@Pointcut?Annotation?時(shí)指定切入點(diǎn)表達(dá)式 ??
- @pointcut ( "execution?*?transfer(..)" )??
- //?使用一個(gè)返回值為void,方法體為空的方法來命名切入點(diǎn) ??
- private ? void ?anyOldTransfer(){}??
- ??
- //?使用上面定義的切入點(diǎn) ??
- @AfterReturning (pointcut= "anyOldTransfer()" ,?returning= "reVal" )??
- public ? void ?writeLog(String?msg,?Object?reVal){??
- ????...??
- }??
// 使用@Pointcut Annotation 時(shí)指定切入點(diǎn)表達(dá)式 @pointcut("execution * transfer(..)") // 使用一個(gè)返回值為void,方法體為空的方法來命名切入點(diǎn) private void anyOldTransfer(){} // 使用上面定義的切入點(diǎn) @AfterReturning(pointcut="anyOldTransfer()", returning="reVal") public void writeLog(String msg, Object reVal){ ... }
?
?
2、基于 XML 配置文件的管理方式。
?
?
- 不配置切入點(diǎn)
?
?
- <?xml?version= "1.0" ?encoding= "UTF-8" ?>??
- <beans?xmlns= "http://www.springframework.org/schema/beans" ??
- ???????xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" ??
- ???????xmlns:aop= "http://www.springframework.org/schema/aop" ????????
- ???????xsi:schemaLocation="http: //www.springframework.org/schema/beans ??
- ???????????http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd ??
- ???????????http: //www.springframework.org/schema/aop ??
- ???????http: //www.springframework.org/schema/beans/spring-aop-3.0.xsd"> ??
- ????????<aop:config>??
- ????????????<!--?將?fourAdviceBean?轉(zhuǎn)換成切面?Bean,?切面?Bean?的新名稱為:fourAdviceAspect,指定該切面的優(yōu)先級(jí)為 2 ?-->??
- ????????????<aop:aspect?id= "fourAdviceAspect" ?ref= "fourAdviceBean" ?order= "2" >??
- ????????????????<!--?定義個(gè)After增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面?Bean?中的?Release()?方法作為增強(qiáng)處理方法?-->??
- ????????????????<aop:after?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" ?method= "release" ?/>??
- ??????????????????
- ????????????????<!--?定義個(gè)Before增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面?Bean?中的?authority()?方法作為增強(qiáng)處理方法?-->??
- ????????????????<aop:before?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" ?method= "authority" ?/>??
- ??????????????????
- ????????????????<!--?定義個(gè)AfterReturning增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面?Bean?中的?log()?方法作為增強(qiáng)處理方法?-->??
- ????????????????<aop:after-returning?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" ?method= "log" ?/>??
- ??????????????????
- ????????????????<!--?定義個(gè)Around增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面?Bean?中的?processTx()?方法作為增強(qiáng)處理方法?-->??
- ????????????????<aop:around?pointcut= "execution(*?com.wicresoft.app.service.impl.*.*(..))" ?method= "processTx" ?/>??
- ??????????????????
- ????????????</aop:aspect>??
- ????????</aop:config>??
- ??????????
- ????????<!--?省略各個(gè)Bean?的配置?-->??
- ????????<!--?...?-->??
- ??????????
- </beans>??
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/beans/spring-aop-3.0.xsd"> <aop:config> <!-- 將 fourAdviceBean 轉(zhuǎn)換成切面 Bean, 切面 Bean 的新名稱為:fourAdviceAspect,指定該切面的優(yōu)先級(jí)為2 --> <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"> <!-- 定義個(gè)After增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面 Bean 中的 Release() 方法作為增強(qiáng)處理方法 --> <aop:after pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> <!-- 定義個(gè)Before增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面 Bean 中的 authority() 方法作為增強(qiáng)處理方法 --> <aop:before pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="authority" /> <!-- 定義個(gè)AfterReturning增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面 Bean 中的 log() 方法作為增強(qiáng)處理方法 --> <aop:after-returning pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="log" /> <!-- 定義個(gè)Around增強(qiáng)處理,直接指定切入點(diǎn)表達(dá)式,以切面 Bean 中的 processTx() 方法作為增強(qiáng)處理方法 --> <aop:around pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="processTx" /> </aop:aspect> </aop:config> <!-- 省略各個(gè)Bean 的配置 --> <!-- ... --> </beans>
?
?
- 配置切入點(diǎn)
?
?
- <?xml?version= "1.0" ?encoding= "UTF-8" ?>??
- <beans?xmlns= "http://www.springframework.org/schema/beans" ??
- ???????xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" ??
- ???????xmlns:aop= "http://www.springframework.org/schema/aop" ????????
- ???????xsi:schemaLocation="http: //www.springframework.org/schema/beans ??
- ???????????http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd ??
- ???????????http: //www.springframework.org/schema/aop ??
- ???????http: //www.springframework.org/schema/beans/spring-aop-3.0.xsd"> ??
- ????????<aop:config>??
- ????????????<!--?定義一個(gè)切入點(diǎn),myPointcut,直接知道它對(duì)應(yīng)的切入點(diǎn)表達(dá)式?-->??
- ????????????<aop:pointcut?id= "myPointcut" ?expression= "execution(*?com.wicresoft.app.service.impl.*.*(..))" ?method= "release" ?/>??
- ????????????<aop:aspect?id= "afterThrowingAdviceAspect" ?ref= "afterThrowingAdviceBean" ?order= "1" >??
- ????????????????<!--?使用上面定于切入點(diǎn)定義增強(qiáng)處理?-->??
- ????????????????<!--?定義一個(gè)AfterThrowing?增強(qiáng)處理,指定切入點(diǎn)以切面?Bean?中的?doRecovertyActions()?方法作為增強(qiáng)處理方法?-->??
- ????????????????<aop:after-throwing?pointcut-ref= "myPointcut" ?method= "doRecovertyActions" ?throwing= "ex" ?/>??
- ????????????</aop:aspect>??
- ????????</aop:config>??
- ??????????
- ????????<!--?省略各個(gè)Bean?的配置?-->??
- ????????<!--?...?-->??
- ??????????
- </beans>??
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/beans/spring-aop-3.0.xsd"> <aop:config> <!-- 定義一個(gè)切入點(diǎn),myPointcut,直接知道它對(duì)應(yīng)的切入點(diǎn)表達(dá)式 --> <aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> <aop:aspect id="afterThrowingAdviceAspect" ref="afterThrowingAdviceBean" order="1"> <!-- 使用上面定于切入點(diǎn)定義增強(qiáng)處理 --> <!-- 定義一個(gè)AfterThrowing 增強(qiáng)處理,指定切入點(diǎn)以切面 Bean 中的 doRecovertyActions() 方法作為增強(qiáng)處理方法 --> <aop:after-throwing pointcut-ref="myPointcut" method="doRecovertyActions" throwing="ex" /> </aop:aspect> </aop:config> <!-- 省略各個(gè)Bean 的配置 --> <!-- ... --> </beans>
?
參考:
《輕量級(jí) Java EE 企業(yè)應(yīng)用實(shí)戰(zhàn)(第三版)》 李剛
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
