AOP:是一種面向切面的編程范式,是一種編程思想,旨在通過分離橫切關注點,提高模塊化,可以跨越對象關注點。Aop的典型應用即spring的事務機制,日志記錄。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。主要功能是:日志記錄,性能統計,安全控制,事務處理,異常處理等等;主要的意圖是:將日志記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中划分出來,通過對這些行為的分離,我們希望可以將它們獨立到非指導業務邏輯的方法中,進而改變這些行為的時候不影響業務邏輯的代碼。
AspectJ和Spring AOP 是AOP的兩種實現方案,Aspectj是aop的java實現方案,是一種編譯期的用注解形式實現的AOP;Spring aop是aop實現方案的一種,它支持在運行期基於動態代理的方式將aspect織入目標代碼中來實現aop,其中動態代理有兩種方式(jdk動態代理和cglib動態代理),這里不展開說。這里有幾個概念,需要正確理解:
joinPoint:連接點。在spring中只支持方法連接點,連接點指的是可以使用advice(增強)的地方,例如一個類中有5個方法,那么這5個方法,那么這5個方法都可以是連接點。
pointcut:切點。可理解為實實在在的連接點,即切入advice(增強)的點。例如一個類中有5個方法,其中有3個方法(連接點)需要織入advice(增強),那么這3個需要織入advice的連接點就是切點。
advice:增強。實際中想要添加的功能,如日志、權限校驗。
advisor:切面。由切點和增強相結合而成,定義增強應用到哪些切點上。
Spring支持AspectJ的注解式切面編程。使用方式如下:
(1)使用@Aspect聲明是一個切面
(2)使用@After、@Before、@Around定義增強(advice),可以直接將攔截規則作為參數(pointcut),其中@Around可以控制目標方法是否執行,並且改變返回結果。
(3)為了使切點復用,可以使用@PointCut專門定義攔截規則,攔截規則方式有兩種:基於注解攔截和基於方法規則攔截,其中注解式攔截能夠很好的控制攔截粒度和獲取豐富的信息,Spring本身在處理事務和數據緩存也是使用此種方式的攔截。
spring-aop使用demo如下:
1、pom.xml,加入以下依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
2、自定義一個注解,作為攔截規則
package powerx.io; 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 Mylog { String level() default "info"; }
3、編寫功能類
package powerx.io; import org.springframework.stereotype.Service; @Service public class UserService { @Mylog(level="debug") public void add() { System.out.println("添加用戶"); } @Mylog public void find() { System.out.println("查看用戶"); } }
package powerx.io; import org.springframework.stereotype.Service; @Service public class StudentService { public void add() { System.out.println("添加student"); } @Mylog(level="debug") public Object update(String name) { System.out.println("更新student"); return "更新成功"; } }
4、切面
package powerx.io; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; 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.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; @Aspect @Component public class LogAspect { @Pointcut("@annotation(powerx.io.Mylog)") public void annotationPointCut() {}; @After("annotationPointCut()") public void after(JoinPoint joinPoint) { MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); Mylog mylog = method.getAnnotation(Mylog.class); System.out.println("日志等級"+ mylog.level()+ "注解式攔截"); } @Before("execution(* powerx.io.StudentService.*(..))") public void before(JoinPoint joinPoint) { MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); System.out.println("方法規則攔截" + method.getName()); } @Around("@annotation(powerx.io.Mylog)&&execution(* powerx.io.StudentService.*(..))") public Object around(ProceedingJoinPoint joinPoint) { Object result = null; Object[] obs = joinPoint.getArgs(); if(obs != null && obs.length >0) { String name = (String) obs[0]; if("zhangsan".equals(name)) { try { result = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } }else { result = "只有張三才允許修改"; } } return result; } }
5、java配置
package powerx.io; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan("powerx.io") @EnableAspectJAutoProxy//啟動Spring對AspectJ的支持 public class JavaConfig { }
6、主類
package powerx.io; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class); UserService us = ac.getBean(UserService.class); us.add(); us.find(); System.out.println("------------------------"); StudentService ss = ac.getBean(StudentService.class); ss.add(); Object ob = ss.update("zhangsan"); System.out.println(ob); System.out.println("------------------------"); Object ob2 = ss.update("lisi"); System.out.println(ob2); ac.close(); } }
運行主類,控制台顯示如下:

