spring aop的環繞通知around功能強大,咱們這裏就不細說,直接上代碼,看着註釋就能明白java
須要的能夠點擊下載源碼git
1.若是使用註解的方式則須要先建立個註解類github
package com.mb.aop; import java.lang.annotation.*; /** * 經常使用註解說明: * 1. RetentionPolicy(保留策略)是一個enum類型,有三個值 * SOURCE -- 這個Annotation類型的信息只會保留在程序源碼裏,源碼若是通過了編譯後,Annotation的數據就會消失,並不會保留在編譯好的.class文件裏 * CLASS -- 這個Annotation類型的信息保留在程序源碼中,同時也會保留在編譯好的.class文件裏面,在執行的時候,並不會把這一些信息加載到虛擬 機(JVM)中去.注意一下,當你沒有設定一個Annotation類型的Retention值時,系統默認值是CLASS。 * RUNTIME -- 在源碼、編譯好的.class文件中保留信息,在執行的時候會把這一些信息加載到JVM中去的。 * * 2.ElementType @Target中的ElementType用來指定Annotation類型能夠用在哪些元素上 * TYPE(類型) -- 在Class,Interface,Enum和Annotation類型上 * FIELD -- 屬性上 * METHOD -- 方法上 * PARAMETER -- 參數上 * CONSTRUCTOR -- 構造函數上 * LOCAL_VARIABLE -- 局部變量 * ANNOTATION_TYPE -- Annotation類型上 * PACKAGE -- 包上 * * 3.Documented -- 讓這個Annotation類型的信息可以顯示在API說明文檔上;沒有添加的話,使用javadoc生成的API文件找不到這個類型生成的信息 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AssertOK { String isLogin() default "false"; }
2.再建立個攔截器,攔截目標方法並在目標方法先後執行操做web
package com.mb.aop; import com.sun.istack.internal.logging.Logger; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.lang.reflect.TypeVariable; @Component @Aspect public class AssertOKAspectj { private Logger logger = Logger.getLogger(this.getClass()); @Pointcut("@annotation(com.mb.aop.AssertOK)") //表示全部帶有AssertOK的註解 public void point(){ } // @Pointcut("execution(* com.mb..*.*(..))") //表示攔截全部com.mb包及子包下的全部的方法 // public void point(){ // // } @Around(value = "point()") public Object assertAround(ProceedingJoinPoint pjp){ //判斷註解標識若是不爲false則,進行登陸 Class<?> aClass = pjp.getTarget().getClass(); //先獲取被織入加強處理的目標對象,再獲取目標類的clazz String methodName = pjp.getSignature().getName(); //先獲取目標方法的簽名,再獲取目標方法的名 logger.info("methodName: "+methodName); // 輸出目標方法名 Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes(); //獲取目標方法參數類型 Object[] args = pjp.getArgs(); //獲取目標方法的入參 for (int i = 0; i < args.length; i++) { logger.info("argsName: "+args[i]); //輸出目標方法的參數 } try { Method method = aClass.getMethod(methodName, parameterTypes); //獲取目標方法 AssertOK annotation = method.getAnnotation(AssertOK.class); //獲取方法上的註解 annotation.isLogin(); //獲取註解函數值 long starttime = System.currentTimeMillis(); Object proceed = pjp.proceed(); //執行目標方法 long exctime = System.currentTimeMillis() - starttime; logger.info("執行時間:"+exctime + "毫秒"); logger.info("proceed: "+proceed); //打印目標方法的return結果 } catch (Throwable throwable) { throwable.printStackTrace(); } return "aop的返回值"; } }
3.這裏爲了多場景驗證,我建立了2個目標類分別是:Login 、QueryAccount spring
package com.mb.request; import com.mb.aop.AssertOK; import org.springframework.stereotype.Component; @Component public class Login { @AssertOK(isLogin = "ture") public String login(String username,String password){ System.out.println(username+" 登陸成功 "+", 登陸的密碼是 "+password); return "登陸成功"; } @AssertOK(isLogin = "false") public String loginOnline(String name,String pwd){ String login = login(name, pwd); System.out.println("login 的返回值:"+login); return "loginOnline 成功"; } }
package com.mb.request; import com.mb.aop.AssertOK; import org.springframework.stereotype.Component; @Component public class QueryAccount { @AssertOK public String queryAccount(){ System.out.println("帳戶查詢成功...."); return "success"; } }
4.配置spring包掃描和自動代碼配置,這裏默認使用的是jdk動態代理apache
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 自動掃描web包 ,將帶有註解的類 歸入spring容器管理 --> <context:component-scan base-package="com.mb"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
5.最後就是須要咱們把pom.xml文件中添加aspectj和spring核心包等app
<?xml version="1.0" encoding="UTF-8"?> <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.mb</groupId> <artifactId>aspectjdemo</artifactId> <version>1.0-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.20.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.7.RELEASE</version> <scope>test</scope> </dependency> </dependencies> </project>
6.以上搞定,下面咱們來作測試,驗證配置的aop是否生效maven
package com.mb.request; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath*:**/applicationContext*.xml"}) public class RequestTest { @Autowired Login login; @Autowired QueryAccount queryAccount; @Test public void loginTest(){ login.loginOnline("米小圈","123456"); } }
7.測試結果:函數
二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj] invoke0 信息: methodName: loginOnline 二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj] invoke0 信息: argsName: 米小圈 二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj] invoke0 信息: argsName: 123456 米小圈 登陸成功 , 登陸的密碼是 123456 login 的返回值:登陸成功 二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj] invoke0 信息: 執行時間:15毫秒 二月 27, 2019 12:04:01 上午 [com.mb.aop.AssertOKAspectj] invoke0 信息: proceed: loginOnline 成功