一个简单的例子,学习自定义注解和AOP
轉(zhuǎn)載自? ?一個(gè)簡(jiǎn)單的例子,學(xué)習(xí)自定義注解和AOP
記得今年年初剛開(kāi)始面試的時(shí)候,被問(wèn)的最多的就是你知道Spring的兩大核心嘛?那你說(shuō)說(shuō)什么是AOP,什么是IOC?我相信你可能也被問(wèn)了很多次了。
?
1、到底是什么是AOP?
所謂AOP也就是面向切面編程,能夠讓我們?cè)诓挥绊懺袠I(yè)務(wù)功能的前提下,橫切擴(kuò)展新的功能。這里面有一個(gè)比較顯眼的詞我們需要注意一下,橫切,它是基于橫切面對(duì)程序進(jìn)行擴(kuò)展的。
?
2、AOP相關(guān)術(shù)語(yǔ)
在Spring的AOP中有很多的術(shù)語(yǔ),而且容易混淆,大家一定要先搞清楚這幾個(gè)概念:
-
連接點(diǎn)(Joinpoint):在程序執(zhí)行過(guò)程中某個(gè)特定的點(diǎn),比如類初始化前、類初始化后,方法調(diào)用前,方法調(diào)用后;
-
切點(diǎn)(Pointcut):所謂切點(diǎn)就是你所切取的類中的方法,比如你橫切的這個(gè)類中有兩個(gè)方法,那么這兩個(gè)方法都是連接點(diǎn),對(duì)這兩個(gè)方法的定位就稱之為切點(diǎn);
-
增強(qiáng)(Advice):增強(qiáng)是織入到連接點(diǎn)上的一段程序,另外它還擁有連接點(diǎn)的相關(guān)信息;
-
目標(biāo)對(duì)象(Target):增強(qiáng)邏輯的織入目標(biāo)類,就是我的增強(qiáng)邏輯植入到什么位置;
-
引介(Introduction):一種特殊的增強(qiáng),它可以為類添加一些屬性喝方法;
-
織入(Weaving):織入就是講增強(qiáng)邏輯添加到目標(biāo)對(duì)象的過(guò)程;
-
代理(Proxy):一個(gè)類被AOP織入增強(qiáng)后,就會(huì)產(chǎn)生一個(gè)結(jié)果類,他是融合了原類和增強(qiáng)邏輯的代理類;
-
切面(Aspect):切面由切點(diǎn)和增強(qiáng)組成,他是橫切邏輯定義和連接點(diǎn)定義的組成;
?
3、AOP功能實(shí)踐
我們這里主要是學(xué)習(xí)SpringBoot中的一些功能,所以我們這里用的是SpringBoot工程,版本也是最新的2.0.5版本。
創(chuàng)建SpringBoot工程就不說(shuō)了,我們直接引入Maven的依賴:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.5.RELEASE</version><relativePath/>?<!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency><!-- 引入AOP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.6.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.20</version><configuration><skip>true</skip></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions></executions></plugin></plugins></build>首先我們來(lái)創(chuàng)建一個(gè)Controller類:
@RestController public?class?LoginController {@GetMapping(value =?"/username")public?String?getLoginUserName(String?userName, Integer age) {return?userName +?" --- "?+ age;} }創(chuàng)建切面:
@Aspect @Component public?class?LogAspect?{/*** 功能描述: 攔截對(duì)這個(gè)包下所有方法的訪問(wèn)** @param:[]* @return:void**/@Pointcut("execution(* com.example.springbootaop.controller.*.*(..))")public?void?loginLog()?{}// 前置通知@Before("loginLog()")public?void?loginBefore(JoinPoint joinPoint)?{// 我們從請(qǐng)求的上下文中獲取request,記錄請(qǐng)求的內(nèi)容ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();System.out.println("請(qǐng)求路徑 : "?+ request.getRequestURL());System.out.println("請(qǐng)求方式 : "?+ request.getMethod());System.out.println("方法名 : "?+ joinPoint.getSignature().getName());System.out.println("類路徑 : "?+ joinPoint.getSignature().getDeclaringTypeName());System.out.println("參數(shù) : "?+ Arrays.toString(joinPoint.getArgs()));}@AfterReturning(returning =?"object", pointcut =?"loginLog()")public?void?doAfterReturning(Object?object)?{System.out.println("方法的返回值 : "?+?object);}// 方法發(fā)生異常時(shí)執(zhí)行該方法@AfterThrowing(throwing =?"e",pointcut =?"loginLog()")public?void?throwsExecute(JoinPoint joinPoint, Exception e)?{System.err.println("方法執(zhí)行異常 : "?+ e.getMessage());}// 后置通知@After("loginLog()")public?void?afterInform()?{System.out.println("后置通知結(jié)束");}// 環(huán)繞通知@Around("loginLog()")public?Object?surroundInform(ProceedingJoinPoint proceedingJoinPoint)?{System.out.println("環(huán)繞通知開(kāi)始...");try?{Object o = ?proceedingJoinPoint.proceed();System.out.println("方法環(huán)繞proceed,結(jié)果是 :"?+ o);return?o;}?catch?(Throwable e) {e.printStackTrace();return?null;}} }注解概述:
-
@Apsect:將當(dāng)前類標(biāo)識(shí)為一個(gè)切面;
-
@Pointcut:定義切點(diǎn),這里使用的是條件表達(dá)式;
-
@Before:前置增強(qiáng),就是在目標(biāo)方法執(zhí)行之前執(zhí)行;
-
@AfterReturning:后置增強(qiáng),方法退出時(shí)執(zhí)行;
-
@AfterThrowing:有異常時(shí)該方法執(zhí)行;
-
@After:最終增強(qiáng),無(wú)論什么情況都會(huì)執(zhí)行;
-
@Afround:環(huán)繞增強(qiáng);
?
測(cè)試:
異常測(cè)試:
?
4、定義自定義注解
應(yīng)用場(chǎng)景:在我之前上個(gè)項(xiàng)目的時(shí)候,有這樣一個(gè)注解,就是在訪問(wèn)其他接口的時(shí)候必須要登錄,那么這個(gè)時(shí)候我們就定義一個(gè)注解,讓它去對(duì)用戶是否登錄進(jìn)行校驗(yàn),那么基于這樣的一個(gè)場(chǎng)景,我們來(lái)定義一個(gè)校驗(yàn)登錄的注解。
創(chuàng)建一個(gè)注解:
@Target({ElementType.METHOD,?ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Auth {String?desc()?default?"驗(yàn)證是否登錄"; }創(chuàng)建一個(gè)AOP切面:
@Aspect @Component public?class?LoginAspect?{@Pointcut(value =?"@annotation(com.example.springbootaop.annotation.Auth)")public?void?access()?{}@Before("access()")public?void?before()?{System.out.println("開(kāi)始驗(yàn)證用戶是否登錄...");}@Around("@annotation(auth)")public?Object?around(ProceedingJoinPoint pj, Auth auth)?{// 獲取注解中的值System.out.println("注解中的值 : "?+ auth.desc());try?{// 檢驗(yàn)是否登錄 true 已經(jīng)登錄 ?false 未登錄Boolean flag =?false;if?(flag ==?true) {return?"登錄成功";}?else?{return?"未登錄";}}?catch?(Throwable throwable) {return?null;}} }測(cè)試未登錄:
測(cè)試登錄:
這樣我們就可以簡(jiǎn)單的實(shí)現(xiàn)了一個(gè)登錄校驗(yàn)的注解。
通過(guò)今天的分享你會(huì)使用AOP和自定義注解了嗎?我把源碼的地址放在下面,有興趣的朋友可以看看。
https://github.com/liangbintao/SpringBootIntegration.git
總結(jié)
以上是生活随笔為你收集整理的一个简单的例子,学习自定义注解和AOP的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Bluehost vs Hostinge
- 下一篇: 如何评价一家四口自驾环中国行环欧亚北极行