Spring 中基於AOP的@AspectJ

@AspectJ 作爲通過 Java 5 註釋註釋的普通的 Java 類,它指的是聲明 aspects 的一種風格。通過在你的基於架構的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的。

<aop:aspectj-autoproxy/>

如果需要使用該註解,需要包含一下幾個包:
- aspectjrt.jar
- aspectjweaver.jar
- aspectj.jar
- aopalliance.jar

Aspects 類就和其他正常的bean一樣,可以有方法和成員,除了該類是用@Aspect 註解的:

package org.xyz;

import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AspectModule {
}

它們就和其他任何一個bean一樣配置在XML中:

<bean id = "myAspect" class = "org.xyz.AspectModule">
   <!-- configure properties of aspect here as normal -->
</bean>

Declaring a pointcut

聲明一個切點:一個切點幫助決定使用不同的advices執行的感興趣的點(比如方法)。當使用@AspectJ-based配置的時候,切點聲明有兩部分。

  • 一個切點表達式確定哪些方法是我感興趣的
  • 切點的特徵包括名稱和任意數量的參數,該方法的實際主體時不想關的,實際上應該是空的。

下面的例子定義了一個名稱爲businessService的切點,該切點匹配com.xyz.myapp.service包中任意類的任意方法

import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression 
private void businessService() {}  // signature

下面的例子定義了一個名稱爲getname的切點,這個切點將匹配com.tutorialspoint包中Student類的getName()方法。

import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.tutorialspoint.Student.getName(..))") 
private void getname() {}

Declaring advices

你可以使用@{ADVICE-NAME}註解聲明任何五種advices中的一種,這些都是在假定你已經定義了一個businessService()切點聲明前提下的。

@Before("businessService()")
public void doBeforeTask(){
   ...
}

@After("businessService()")
public void doAfterTask(){
   ...
}

@AfterReturning(pointcut = "businessService()", returning = "retVal")
public void doAfterReturnningTask(Object retVal) {
   // you can intercept retVal here.
   ...
}

@AfterThrowing(pointcut = "businessService()", throwing = "ex")
public void doAfterThrowingTask(Exception ex) {
  // you can intercept thrown exception here.
  ...
}

@Around("businessService()")
public void doAroundTask(){
   ...
}

你也可以在advices中定義一個切點,下面就是一個例子:

@Before("execution(* com.xyz.myapp.service.*.*(..))")
public doBeforeTask(){
   ...
}

@AspectJ Based AOP Example

Student.java

package com.soygrow.AspectJAnnotation;

public class Student {
    private Integer age;
    private String name;

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        System.out.println("Name : " + name);
        return name;
    }

    public Integer getAge() {
        System.out.println("Age : " + age);
        return age;
    }

    public void printThrowException() {
        System.out.println("Exception raised");
        throw  new IllegalArgumentException();
    }
}

Logging.java

package com.soygrow.AspectJAnnotation;

import org.aspectj.lang.annotation.*;

@Aspect
public class Logging {
    /**
     * Following is the definition for a pointcut to select
     * all the methods available. So advices will be called
     * for all the methods.
     */
    @Pointcut("execution(* com.soygrow.AspectJAnnotation.*.*(..))")
    private void selectAll() {
    }

    /**
     * This is the method which I would like to execute
     * before a selected method execution.
     */
    @Before("selectAll()")
    public void beforeAdvice() {
        System.out.println("Going to setup student profile.");
    }

    /**
     * This is the method which I would like to execute
     * after a selected method execution.
     */
    @After("selectAll()")
    public void afterAdvice() {
        System.out.println("Student profile has been setup.");
    }

    /**
     * This is the method which I would like to execute
     * when any method returns.
     */
    @AfterReturning(pointcut = "selectAll()", returning = "object")
    public void afterReturningAdvice(Object object) {
        System.out.println("Returning : " + object.toString());
    }

    /**
     * This is the method which I would like to execute
     * if there is an exception raised by any method.
     */
    @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
    public void AfterThrowingAdvice(IllegalArgumentException ex) {
        System.out.println("There has been an exception : " + ex.toString());
    }
}

MainApp.java

package com.soygrow.AspectJAnnotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("AspectJBeans.xml");
        Student student = (Student) context.getBean("student");
        student.getAge();
        student.getName();

        student.printThrowException();
    }
}

AspectJBeans.xml

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>

    <!-- Definition for student bean -->
    <bean id = "student" class = "com.soygrow.AspectJAnnotation.Student">
        <property name = "name" value = "Zara" />
        <property name = "age"  value = "11"/>
    </bean>

    <!-- Definition for logging aspect -->
    <bean id = "logging" class = "com.soygrow.AspectJAnnotation.Logging"/>
</beans>

如果一切正常,運行結果:

Going to setup student profile.
Age : 11
Student profile has been setup.
Returning : 11
Going to setup student profile.
Name : Zara
Student profile has been setup.
Returning : Zara
Going to setup student profile.
Exception raised
Student profile has been setup.
There has been an exception : java.lang.IllegalArgumentException

如果在XML配置文件中去掉<aop:aspectj-autoproxy/>,那麼就不會運行AspectJ相關代碼

遇到的問題

Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘student’ defined in class path resource [AspectJBeans.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can’t find referenced pointcut selectAll
at

問題是我用的AspectJ庫文件的版本過低導致的,將版本從1.5.4升級到1.7.4就沒有這個問題了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章