spring項目中aop的使用


  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();
    }
}

  運行主類,控制台顯示如下:

 


免責聲明!

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



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