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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring学习总结——Spring实现AOP的多种方式

發(fā)布時(shí)間:2025/3/21 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring学习总结——Spring实现AOP的多种方式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 一、基于XML配置的Spring AOP
  • 二、使用注解配置AOP
  • 三、AspectJ切點(diǎn)函數(shù)
  • 四、AspectJ通知注解
  • 五、零配置實(shí)現(xiàn)Spring IoC與AOP
  • 六、示例下載

AOP(Aspect Oriented Programming)面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的橫向多模塊統(tǒng)一控制的一種技術(shù)。AOP是OOP的補(bǔ)充,是spring框架中的一個(gè)重要內(nèi)容。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率。AOP可以分為靜態(tài)織入與動(dòng)態(tài)織入,靜態(tài)織入即在編譯前將需織入內(nèi)容寫(xiě)入目標(biāo)模塊中,這樣成本非常高。動(dòng)態(tài)織入則不需要改變目標(biāo)模塊。Spring框架實(shí)現(xiàn)了AOP,使用注解配置完成AOP比使用XML配置要更加方便與直觀。上一篇隨筆中已經(jīng)詳細(xì)講了代理模式。

一、基于XML配置的Spring AOP

在講注解實(shí)現(xiàn)AOP功能前先用前面學(xué)習(xí)過(guò)的使用xml配置Spring AOP功能,這樣是為了對(duì)比以便更好的理解。

1.1、新建一個(gè)Maven項(xiàng)目,添加引用,項(xiàng)目的pom.xml文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zhangguo</groupId><artifactId>Spring052</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>Spring052</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>4.3.0.RELEASE</spring.version></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope><version>4.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.4</version></dependency></dependencies> </project>

1.2、創(chuàng)建要被代理的Math類(lèi),代碼如下:

package com.zhangguo.Spring052.aop01;/*** 被代理的目標(biāo)類(lèi)*/ public class Math{//public int add(int n1,int n2){int result=n1+n2;System.out.println(n1+"+"+n2+"="+result);return result;}//public int sub(int n1,int n2){int result=n1-n2;System.out.println(n1+"-"+n2+"="+result);return result;}//public int mut(int n1,int n2){int result=n1*n2;System.out.println(n1+"X"+n2+"="+result);return result;}//public int div(int n1,int n2){int result=n1/n2;System.out.println(n1+"/"+n2+"="+result);return result;} }

1.3、編輯AOP中需要使用到的通知類(lèi)Advices.Java代碼如下:

package com.zhangguo.Spring052.aop01;import org.aspectj.lang.JoinPoint;/*** 通知類(lèi),橫切邏輯**/ public class Advices {public void before(JoinPoint jp){System.out.println("----------前置通知----------");System.out.println(jp.getSignature().getName());}public void after(JoinPoint jp){System.out.println("----------最終通知----------");} }

1.4、配置容器初始化時(shí)需要的XML文件,aop01.xml文件內(nèi)容如下:

<?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:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><!-- 被代理對(duì)象 --><bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean><!-- 通知 --><bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean><!-- aop配置 --><aop:config proxy-target-class="true"><!--切面 --><aop:aspect ref="advices"><!-- 切點(diǎn) --><aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/><!--連接通知方法與切點(diǎn) --><aop:before method="before" pointcut-ref="pointcut1"/><aop:after method="after" pointcut-ref="pointcut1"/></aop:aspect></aop:config></beans>

1.5、測(cè)試代碼Test.java如下:

package com.zhangguo.Spring052.aop01;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("aop01.xml");Math math = ctx.getBean("math", Math.class);int n1 = 100, n2 = 5;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);math.div(n1, n2);}}

運(yùn)行結(jié)果:

二、使用注解配置AOP

2.1、在上一個(gè)示例中修改被代理的類(lèi)Math,為了實(shí)現(xiàn)IOC掃描在Math類(lèi)上注解了@Service并命名bean為math。相當(dāng)于上一個(gè)示例中在xml配置文件中增加了一個(gè)bean,<!-- 被代理對(duì)象 --><bean id="math" class="com.zhangguo.Spring052.aop01.Math"></bean>,Math類(lèi)的代碼如下:

package com.zhangguo.Spring052.aop02;import org.springframework.stereotype.Service;/*** 被代理的目標(biāo)類(lèi)*/ @Service("math") public class Math{//public int add(int n1,int n2){int result=n1+n2;System.out.println(n1+"+"+n2+"="+result);return result;}//public int sub(int n1,int n2){int result=n1-n2;System.out.println(n1+"-"+n2+"="+result);return result;}//public int mut(int n1,int n2){int result=n1*n2;System.out.println(n1+"X"+n2+"="+result);return result;}//public int div(int n1,int n2){int result=n1/n2;System.out.println(n1+"/"+n2+"="+result);return result;} }

?2.2、修改通知類(lèi)Advices,代碼中有3個(gè)注解,@Component表示該類(lèi)的實(shí)例會(huì)被Spring IOC容器管理;@Aspect表示聲明一個(gè)切面;@Before表示before為前置通知,通過(guò)參數(shù)execution聲明一個(gè)切點(diǎn),Advices.java代碼如下所示:

package com.zhangguo.Spring052.aop02;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;/*** 通知類(lèi),橫切邏輯**/ @Component @Aspect public class Advices {@Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")public void before(JoinPoint jp){System.out.println("----------前置通知----------");System.out.println(jp.getSignature().getName());}@After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")public void after(JoinPoint jp){System.out.println("----------最終通知----------");} }

?上面的代碼與下面的配置基本等同

<!-- 通知 --><bean id="advices" class="com.zhangguo.Spring052.aop01.Advices"></bean><!-- aop配置 --><aop:config proxy-target-class="true"><!--切面 --><aop:aspect ref="advices"><!-- 切點(diǎn) --><aop:pointcut expression="execution(* com.zhangguo.Spring052.aop01.Math.*(..))" id="pointcut1"/><!--連接通知方法與切點(diǎn) --><aop:before method="before" pointcut-ref="pointcut1"/><aop:after method="after" pointcut-ref="pointcut1"/></aop:aspect></aop:config>

2.3、新增配置文件aop02.xml,在配置IOC的基礎(chǔ)上增加了aop:aspectj-autoproxy節(jié)點(diǎn),Spring框架會(huì)自動(dòng)為與AspectJ切面配置的Bean創(chuàng)建代理,proxy-target-class="true"屬性表示被代理的目標(biāo)對(duì)象是一個(gè)類(lèi),而非實(shí)現(xiàn)了接口的類(lèi),主要是為了選擇不同的代理方式。

<?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:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.3.xsd"><context:component-scan base-package="com.zhangguo.Spring052.aop02"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>

2.4、測(cè)試運(yùn)行代碼Test.java如下:

package com.zhangguo.Spring052.aop02;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("aop02.xml");Math math = ctx.getBean("math", Math.class);int n1 = 100, n2 = 5;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);math.div(n1, n2);}}

運(yùn)行結(jié)果:

三、AspectJ切點(diǎn)函數(shù)

切點(diǎn)函數(shù)可以定位到準(zhǔn)確的橫切邏輯位置,在前面的示例中我們只使用過(guò)execution(* com.zhangguo.Spring052.aop02.Math.*(..)),execution就是一個(gè)切點(diǎn)函數(shù),但該函數(shù)只什么方法一級(jí),如果我們要織入的范圍是類(lèi)或某個(gè)注解則execution就不那么好用了,其實(shí)一共有9個(gè)切點(diǎn)函數(shù),有不同的針對(duì)性。

@AspectJ使用AspectJ專(zhuān)門(mén)的切點(diǎn)表達(dá)式描述切面,Spring所支持的AspectJ表達(dá)式可分為四類(lèi):
方法切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類(lèi)方法信息定義連接點(diǎn)。
方法參數(shù)切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類(lèi)方法入?yún)⑿畔⒍x連接點(diǎn)。
目標(biāo)類(lèi)切點(diǎn)函數(shù):通過(guò)描述目標(biāo)類(lèi)類(lèi)型信息定義連接點(diǎn)。
代理類(lèi)切點(diǎn)函數(shù):通過(guò)描述代理類(lèi)信息定義連接點(diǎn)。

常見(jiàn)的AspectJ表達(dá)式函數(shù):
execution():滿(mǎn)足匹配模式字符串的所有目標(biāo)類(lèi)方法的連接點(diǎn)
@annotation():任何標(biāo)注了指定注解的目標(biāo)方法鏈接點(diǎn)
args():目標(biāo)類(lèi)方法運(yùn)行時(shí)參數(shù)的類(lèi)型指定連接點(diǎn)
@args():目標(biāo)類(lèi)方法參數(shù)中是否有指定特定注解的連接點(diǎn)
within():匹配指定的包的所有連接點(diǎn)
target():匹配指定目標(biāo)類(lèi)的所有方法
@within():匹配目標(biāo)對(duì)象擁有指定注解的類(lèi)的所有方法
@target():匹配當(dāng)前目標(biāo)對(duì)象類(lèi)型的執(zhí)行方法,其中目標(biāo)對(duì)象持有指定的注解
this():匹配當(dāng)前AOP代理對(duì)象類(lèi)型的所有執(zhí)行方法

最常用的是:execution(<修飾符模式>?<返回類(lèi)型模式><方法名模式>(<參數(shù)模式>)<異常模式>?)切點(diǎn)函數(shù),可以滿(mǎn)足多數(shù)需求。

為了展示各切點(diǎn)函數(shù)的功能現(xiàn)在新增一個(gè)類(lèi)StrUtil,類(lèi)如下:

package com.zhangguo.Spring052.aop03;import org.springframework.stereotype.Component;@Component("strUtil") public class StrUtil {public void show(){System.out.println("Hello StrUtil!");} }

測(cè)試代碼如下:

package com.zhangguo.Spring052.aop03;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("aop03.xml");IMath math = ctx.getBean("math", Math.class);int n1 = 100, n2 = 5;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);math.div(n1, n2);StrUtil strUtil=ctx.getBean("strUtil",StrUtil.class);strUtil.show();}}

3.1、切點(diǎn)函數(shù)execution,通知與切面的定義如下:

package com.zhangguo.Spring052.aop03;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;/*** 通知類(lèi),橫切邏輯**/ @Component @Aspect public class Advices {@Before("execution(* com.zhangguo.Spring052.aop03.Math.*(..))")public void before(JoinPoint jp){System.out.println("----------前置通知----------");System.out.println(jp.getSignature().getName());}//execution切點(diǎn)函數(shù)//com.zhangguo.Spring052.aop03包下所有類(lèi)的所有方法被切入@After("execution(* com.zhangguo.Spring052.aop03.*.*(..))")public void after(JoinPoint jp){System.out.println("----------最終通知----------");} }

運(yùn)行結(jié)果如下:

execution(<修飾符模式>?<返回類(lèi)型模式><方法名模式>(<參數(shù)模式>)<異常模式>?)

3.2、切點(diǎn)函數(shù)within

//within切點(diǎn)函數(shù)//com.zhangguo.Spring052.aop03包下所有類(lèi)的所有方法被切入@After("within(com.zhangguo.Spring052.aop03.*)")public void after(JoinPoint jp){System.out.println("----------最終通知----------");}

?

3.3、this切點(diǎn)函數(shù)

//this切點(diǎn)函數(shù)//實(shí)現(xiàn)了IMath接口的代理對(duì)象的任意連接點(diǎn)@After("this(com.zhangguo.Spring052.aop03.IMath)")public void after(JoinPoint jp){System.out.println("----------最終通知----------");}

3.4、args切點(diǎn)函數(shù)

//args切點(diǎn)函數(shù)//要求方法有兩個(gè)int類(lèi)型的參考才會(huì)被織入橫切邏輯@After("args(int,int)")public void after(JoinPoint jp){System.out.println("----------最終通知----------");}

?

如果參數(shù)類(lèi)型不是基本數(shù)據(jù)類(lèi)型則需要包名。

3.5、@annotation切點(diǎn)函數(shù)

先自定義一個(gè)可以注解在方法上的注解

package com.zhangguo.Spring052.aop03;import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnno { } //@annotation切點(diǎn)函數(shù)//要求方法必須被注解com.zhangguo.Spring052.aop03.MyAnno才會(huì)被織入橫切邏輯@After("@annotation(com.zhangguo.Spring052.aop03.MyAnno)")public void after(JoinPoint jp){System.out.println("----------最終通知----------");} package com.zhangguo.Spring052.aop03;import org.springframework.stereotype.Component;@Component("strUtil") public class StrUtil {@MyAnnopublic void show(){System.out.println("Hello StrUtil!");} }

運(yùn)行結(jié)果:

其它帶@的切點(diǎn)函數(shù)都是針對(duì)注解的

四、AspectJ通知注解

AspectJ通知注解共有6個(gè),常用5個(gè),引介少用一些。

先解決定義切點(diǎn)復(fù)用的問(wèn)題,如下代碼所示,切點(diǎn)函數(shù)的內(nèi)容完全一樣:

package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;/*** 通知類(lèi),橫切邏輯**/ @Component @Aspect public class Advices {@Before("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")public void before(JoinPoint jp){System.out.println("----------前置通知----------");System.out.println(jp.getSignature().getName());}@After("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")public void after(JoinPoint jp){System.out.println("----------最終通知----------");} }

可以先定義一個(gè)切點(diǎn)然后復(fù)用,如下所示:

package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;/*** 通知類(lèi),橫切邏輯*/ @Component @Aspect public class Advices {//切點(diǎn)@Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.*(..))")public void pointcut(){}@Before("pointcut()")public void before(JoinPoint jp){System.out.println("----------前置通知----------");System.out.println(jp.getSignature().getName());}@After("pointcut()")public void after(JoinPoint jp){System.out.println("----------最終通知----------");} }

修改Advices.java文件,增加各種通知類(lèi)型如下:

package com.zhangguo.Spring052.aop04;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;/*** 通知類(lèi),橫切邏輯*/ @Component @Aspect public class Advices {//切點(diǎn)@Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))")public void pointcut(){}//前置通知@Before("pointcut()")public void before(JoinPoint jp){System.out.println(jp.getSignature().getName());System.out.println("----------前置通知----------");}//最終通知@After("pointcut()")public void after(JoinPoint jp){System.out.println("----------最終通知----------");}//環(huán)繞通知@Around("execution(* com.zhangguo.Spring052.aop04.Math.s*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable{System.out.println(pjp.getSignature().getName());System.out.println("----------環(huán)繞前置----------");Object result=pjp.proceed();System.out.println("----------環(huán)繞后置----------");return result;}//返回結(jié)果通知@AfterReturning(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.m*(..))",returning="result")public void afterReturning(JoinPoint jp,Object result){System.out.println(jp.getSignature().getName());System.out.println("結(jié)果是:"+result);System.out.println("----------返回結(jié)果----------");}//異常后通知@AfterThrowing(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.d*(..))",throwing="exp")public void afterThrowing(JoinPoint jp,Exception exp){System.out.println(jp.getSignature().getName());System.out.println("異常消息:"+exp.getMessage());System.out.println("----------異常通知----------");} }

運(yùn)行結(jié)果:

五、零配置實(shí)現(xiàn)Spring IoC與AOP

為了實(shí)現(xiàn)零配置在原有示例的基礎(chǔ)上我們新增一個(gè)類(lèi)User,如下所示:

package com.zhangguo.Spring052.aop05;public class User {public void show(){System.out.println("一個(gè)用戶(hù)對(duì)象");} }

該類(lèi)并未注解,容器不會(huì)自動(dòng)管理。因?yàn)闆](méi)有xml配置文件,則使用一個(gè)作為配置信息,ApplicationCfg.java文件如下:

package com.zhangguo.Spring052.aop05;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration //用于表示當(dāng)前類(lèi)為容器的配置類(lèi),類(lèi)似<beans/> @ComponentScan(basePackages="com.zhangguo.Spring052.aop05") //掃描的范圍,相當(dāng)于xml配置的結(jié)點(diǎn)<context:component-scan/> @EnableAspectJAutoProxy(proxyTargetClass=true) //自動(dòng)代理,相當(dāng)于<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> public class ApplicationCfg {//在配置中聲明一個(gè)bean,相當(dāng)于<bean id=getUser class="com.zhangguo.Spring052.aop05.User"/>@Beanpublic User getUser(){return new User();} }

該類(lèi)的每一部分內(nèi)容基本都與xml 配置有一對(duì)一的關(guān)系,請(qǐng)看注釋,這樣做要比寫(xiě)xml方便,但不便發(fā)布后修改。測(cè)試代碼如下:

package com.zhangguo.Spring052.aop05;import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {// 通過(guò)類(lèi)初始化容器ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationCfg.class);Math math = ctx.getBean("math", Math.class);int n1 = 100, n2 = 0;math.add(n1, n2);math.sub(n1, n2);math.mut(n1, n2);try {math.div(n1, n2);} catch (Exception e) {}User user=ctx.getBean("getUser",User.class);user.show();}}

?advices.java 同上,沒(méi)有任何變化,運(yùn)行結(jié)果如下:


from:?http://blog.csdn.net/u010987379/article/details/52152925

總結(jié)

以上是生活随笔為你收集整理的Spring学习总结——Spring实现AOP的多种方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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