對於AOP的這種編程思想,有不少框架或者組件進行了實現,spring實現AOP就是其中的一種。java
AspectJ也實現了AOP,並且實現方式更爲簡單,使用起來更爲方便,因此spring將AspectJ對於AOP的實現引入了本身的框架。spring
AspectJ是一個面向切面的框架,它定義了AOP的一些語法,有一個專門的字節碼生成器來生成遵照java規範的class文件。express
AspectJ的通知類型:編程
切入點表達式做用:標識切面織入到哪些類的哪些方法當中。app
public boolean com.steven.spring.service.impl.StudentService.addStudent(Student student) execution( modifiers-pattern? //訪問權限匹配 如public、protected 問號表明能夠省略 ret-type-pattern //返回值類型匹配 declaring-type-pattern? //全限定性類名 name-pattern(param-pattern) //方法名(參數名) throws-pattern? //拋出異常類型 )
注意:中間以空格隔開,有問號的屬性能夠省略框架
a: * 表明0到多個任意字符 b: .. 放在方法參數中 ,表明任意個參數 ,放在包名後面表示當前包及其全部子包路徑 c: + 放在類名後,表示當前類及其子類,放在接口後,表示當前接口及其實現類
a:execution(public * *(..)) 表示任意的public方法 b:execution(* set*(..)) 表示任意包含以set字符開頭的方法 c:execution(* com.steven.spring.service.impl.*.*(..)) 表示com.steven.spring.service.impl的任意類的任意方法 d:execution(* com.steven.spring.service..*.*(..)) 表示com.steven.spring.service包下面的全部方法以及全部子包下面的全部方法 e:execution(* com.steven.spring.service.IStudentService+.*(..)) f:execution(* add(String,int)) 帶包任意返回類型的add方法 有兩個參數,類型分別爲String,int g:execution(* add(String,*))
引入jar包jsp
經測試,能夠不用另外加上spring-aspects-4.2.1.RELEASE.jar。但aspectjweaver必定不能少。ide
引入aop的約束測試
實現步驟:this
實例:
1)實體類
package com.steven.spring.sysmanage.entity; /** * 學生實體類 * @author Administrator * */ public class Student implements java.io.Serializable{ private static final long serialVersionUID = -3875695558042397898L; private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
2)服務類接口
package com.steven.spring.sysmanage.service; import java.util.List; import com.steven.spring.sysmanage.entity.Student; /** * 用於對外提供學生服務類的增刪改查接口 * @author Administrator * */ public interface IStudentService { public boolean addStudent(Student student); public boolean delStudent(Integer studentId); public boolean updateStudent(Student student); public List<Student> getStudentList(); }
3)服務類
package com.steven.spring.sysmanage.service.impl; import java.util.ArrayList; import java.util.List; import com.steven.spring.sysmanage.entity.Student; import com.steven.spring.sysmanage.service.IStudentService; /** * 用於對外提供學生服務類的增刪改查實現 * @author Administrator * */ public class StudentService implements IStudentService{ @Override public boolean addStudent(Student student) { //System.out.println("進行權限驗證"); System.out.println("執行增長功能"); //System.out.println("進行日誌記錄"); return true; } @Override public boolean delStudent(Integer studentId) { //System.out.println("進行權限驗證"); int i= 1/0; System.out.println("執行刪除功能"); //System.out.println("進行日誌記錄"); return true; } @Override public boolean updateStudent(Student student) { //System.out.println("進行權限驗證"); System.out.println("執行修改功能"); //System.out.println("進行日誌記錄"); return true; } @Override public List<Student> getStudentList() { //System.out.println("進行權限驗證"); System.out.println("執行查詢功能"); //System.out.println("進行日誌記錄"); return new ArrayList<Student>(); } }
4)定義通知
package com.steven.spring.sysmanage.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * 基於xml配置方式實現aspectJ 定義通知 * @author chenyang * */ public class MyAspect { //定義前置通知 public void beforeAdvice(){ System.out.println("這是一個前置通知,應該在目標方法以前打印出來"); } //定義後置通知 public void afterAdvice(){ System.out.println("這是一個後置通知,應該在目標方法以後打印出來"); } //定義後置通知,包含返回值 public void afterAdvice(Object result){ System.out.println("這是一個後置通知,應該在目標方法以後打印出來;目標方法的返回值爲:" + result.toString()); } //定義環繞通知 public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("這是一個環繞通知,應該在目標方法以前打印出來"); Object result = pjp.proceed(); System.out.println("這是一個環繞通知,應該在目標方法以後打印出來"); } //定義異常通知 public void afterThrowingAdvice(){ System.out.println("這是一個異常通知,應該在目標方法出現異常以後打印出來"); } //定義異常通知,包含返回值 public void afterThrowingAdvice(Exception ex){ System.out.println("這是一個異常通知,應該在目標方法出現異常以後打印出來,異常爲:" + ex); } //定義最終通知 public void lastAdvice(){ System.out.println("這是一個最終通知,不管如何都會執行"); } }
5)配置文件
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 註冊目標類 --> <bean id="studentService" class="com.steven.spring.sysmanage.service.impl.StudentService"></bean> <!-- 註冊切面(通知) --> <bean id="myAspect" class="com.steven.spring.sysmanage.aspect.MyAspect"></bean> <!-- AspectJ的aop配置 --> <aop:config> <aop:pointcut expression="execution(* add*(..))" id="beforePointCut"/> <aop:pointcut expression="execution(* update*(..))" id="afterPointCut"/> <aop:pointcut expression="execution(* get*(..))" id="aroundPointCut"/> <aop:pointcut expression="execution(* del*(..))" id="afterThrowingPointCut"/> <aop:pointcut expression="execution(* del*(..))" id="lastPointCut"/> <aop:aspect ref="myAspect"> <aop:before method="beforeAdvice" pointcut-ref="beforePointCut"/> <aop:after-returning method="afterAdvice" pointcut-ref="afterPointCut" /> <!-- 方法參數必須是全路徑類名 返回值參數名必須與方法中參數名一致 --> <aop:after-returning method="afterAdvice(java.lang.Object)" pointcut-ref="afterPointCut" returning="result" /> <aop:around method="aroundAdvice" pointcut-ref="aroundPointCut"/> <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="afterThrowingPointCut"/> <aop:after-throwing method="afterThrowingAdvice(java.lang.Exception)" pointcut-ref="afterThrowingPointCut" throwing="ex" /> <aop:after method="lastAdvice" pointcut-ref="lastPointCut"/> </aop:aspect> </aop:config> </beans>
6)測試
package com.steven.spring.sysmanage.test; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.steven.spring.sysmanage.entity.Student; import com.steven.spring.sysmanage.service.IStudentService; public class AspectXmlTest { private ApplicationContext ac = null; private IStudentService studentService = null; @Before public void init(){ ac = new ClassPathXmlApplicationContext("applicationContext.xml"); studentService = (IStudentService) ac.getBean("studentService"); } //測試前置通知 @Test public void testBeforeAdvice(){ studentService.addStudent(new Student()); } //測試後置通知 @Test public void testAfterAdvice(){ studentService.updateStudent(new Student()); } //測試環繞通知 @Test public void testAroundAdvice(){ studentService.getStudentList(); } //測試異常通知 @Test public void testAfterThrowingAdvice(){ studentService.delStudent(1); } //測試最終通知 @Test public void testLastAdvice(){ studentService.delStudent(1); } }
註解方式有必定的侵入性(在代碼中加入本來不屬於代碼的部分)。
實現步驟:
實例:
在6.4.1實例的基礎上更改通知類和配置文件,最後在測試類中更改配置文件名稱便可。
1)通知類
package com.steven.spring.sysmanage.aspect; 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; /** * 基於xml配置方式來實現AspectJ 定義通知 * @author Administrator * */ @Aspect public class MyAspectAnnotation { //定義前置通知 @Before(value="execution(* add*(..))") public void beforeAdvice(){ System.out.println("這是一個前置通知,應該在目標方法以前打印出來"); } //定義後置通知 @AfterReturning(value="execution(* update*(..))") public void afterAdvice(){ System.out.println("這是一個後置通知,應該在目標方法以後打印出來"); } //定義後置通知包含返回值 @AfterReturning(value="execution(* update*(..))",returning="result") public void afterAdvice(Object result){ System.out.println("這是一個後置通知,應該在目標方法以後打印出來"); System.out.println("後置通知獲得目標方法的返回值="+result.toString()); } //定義環繞通知 @Around(value="execution(* get*(..))") public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("這是一個環繞通知,應該在目標方法以前打印出來"); Object result = pjp.proceed(); System.out.println("這是一個環繞通知,應該在目標方法以後打印出來"); } //定義異常通知 @AfterThrowing(value="execution(* del*(..))") public void afterThrowingAdvice(){ System.out.println("這是一個異常通知,應該在目標方法出現異常時候打印出來"); } //定義異常通知 @AfterThrowing(value="execution(* del*(..))",throwing="ex") public void afterThrowingAdvice(Exception ex){ System.out.println("這是一個異常通知,應該在目標方法出現異常時候打印出來 ex="+ex); } //定義最終通知 finally @After(value="execution(* del*(..))") public void lastAdvice(){ System.out.println("這是一個最終通知,不管如何會執行 "); } }
2)配置文件
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--註冊studentService --> <bean id = "studentService" class = "com.steven.spring.sysmanage.service.impl.StudentService"> </bean> <!--註冊切面 --> <bean id= "myAspect" class = "stevenm.tz.spring.sysmanage.aspect.MyAspectAnnotation"></bean> <aop:aspectj-autoproxy/> </beans>