Spring中基於AOP的@AspectJ


以下內容引用自http://wiki.jikexueyuan.com/project/spring/aop-with-spring-framenwork/aspectj-based-aop-with-spring.html

@AspectJ是指將Java方法注解為Java 5注解的常規Java類的方式。通過在基於XML Schema的配置文件中包含以下元素來啟用@AspectJ支持。

<aop:aspectj-autoproxy/>

還需要使用以下AspectJ庫:

   <!-- aspectjrt.jar -->
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.10</version>
    </dependency>

    <!-- aspectjweaver。jar -->
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.10</version>
    </dependency>

集成步驟:

1、聲明一個aspect(方面)

Aspects類和其他任何正常的bean一樣,除了它們將會用@AspectJ注解之外,它和其他類一樣可能有方法和字段,如下所示:

package org.xyz;

import org.aspectj.lang.annotation.Aspect;

@Aspect public class AspectModule {

}

它們將在XML中按照如下進行配置,就和其他任何bean一樣:

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

2、聲明一個pointcut(切入點)

切入點有助於確定要用不同建議執行的關聯點(即方法)。在使用基於@AspectJ的配置時,切入點聲明有兩部分:

  • 一個切入點表達式,確定我們要用哪些方法執行。

  • 包括名稱和任意數量的參數的切入點簽名。該方法的實體是無關緊要的,其實應該是空的。

以下示例定義了一個名為“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() {}

提示:

①類似:“execution(*com.tutorialspoint.Student.getName(..))”這樣的語法叫做AspectJ切入點語法,參考:http://www.cnblogs.com/EasonJim/p/6901806.html

②官方文檔關於AspectJ的介紹:https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj

3、聲明建議(通知類型)

你可以使用代碼片段中給出的@{ADVICE-NAME}注釋聲明建議五個中的任何一個。這假設你已經定義了一個切入點簽名方法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(){
   ...
}

你可以為任何建議內聯定義切入點。以下是在建議之前定義內聯切入點的示例:

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

可以看出代碼上的自由度還是非常高的,比如這個在XML中無法實現。

例子:

pom.xml:

<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.jsoft.testspring</groupId>
  <artifactId>testaopaspectj</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>testaopaspectj</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <!-- Spring Core --> <!-- http://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.4.RELEASE</version> </dependency>
     
    <!-- Spring Context --> <!-- http://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.4.RELEASE</version> </dependency> <!-- String AOP --> <!-- http://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.4.RELEASE</version> </dependency> <!-- aspectjrt.jar --> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.10</version> </dependency> <!-- aspectjweaver.jar --> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency>
    
  </dependencies>
</project>

Student.java:

package com.jsoft.testspring.testaopaspectj;

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

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

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

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

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

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

Logging.java:

package com.jsoft.testspring.testaopaspectj;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect public class Logging {

       @Pointcut("execution(* com.jsoft.testspring..*.*(..))") private void selectAll(){}

       @Before("selectAll()") public void beforeAdvice(){
          System.out.println("Going to setup student profile.");
       }

       @After("selectAll()") public void afterAdvice(){
          System.out.println("Student profile has been setup.");
       }

       @AfterReturning(pointcut="selectAll()", returning="retVal") public void afterReturningAdvice(Object retVal){
          System.out.println("Returning:" + retVal.toString() );
       }

       @AfterThrowing(pointcut="selectAll()", throwing="ex") public void AfterThrowingAdvice(IllegalArgumentException ex){
          System.out.println("There has been an exception: " + ex.toString());   
       }  
}

beans.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/>

   <bean id="student" class="com.jsoft.testspring.testaopaspectj.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>      
   </bean>

   <bean id="logging" class="com.jsoft.testspring.testaopaspectj.Logging"/> 

</beans>

這里定義looging的bean是用於實例化。

App.java:

package com.jsoft.testspring.testaopaspectj;

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

/**
 * Hello world!
 *
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); student.getName(); student.getAge(); student.printThrowException();
    }
}

測試結果:

 

測試工程:https://github.com/easonjim/5_java_example/tree/master/springtest/test16/testaopaspectj


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM