手撕Spring5框架(六)基于注解方式实现AOP具体操作

Spring框架一般是基于AspectJ实现AOP操作

什么是AspectJ?

AspectJ是独立的框架,可以和Spring一起用,完成Spring AOP的操作。

基于AspectJ实现Spring AOP具体实现方式分为两种:

  • 基于XML配置文件

  • 基于注解方式

实现具体操作前的准备工作:

1)环境搭建,引入相关依赖

 <!-- spring-aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.2.0</version>
        </dependency>

        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>

基于注解方式实现AOP的具体操作

  1. 开启注解扫描和开启Aspect生成代理对象

package org.learn.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

//Configuration,让Spring知道这是个配置类
@Configuration
@ComponentScan(basePackages = {"org.learn.spring5"})
@EnableAspectJAutoProxy
public class SpringConfig {
}

   2.创建类,在类里定义方法,并通过注解的方式完成对象的创建。

package org.learn.spring5.service.impl;

import org.learn.spring5.service.UserService;
import org.springframework.stereotype.Service;

@Service  //1
public class UserServiceImpl implements UserService {

    //2
    public void add() {
        System.out.println("add");
    }

    public void del() {
        System.out.println("del");
    }

    public void update() {
        System.out.println("update");
    }

    public void query() {
        System.out.println("query");
    }
}

   3.对类中的方法进行增强:

   1)创建一个增强的类

   2)实现增强的逻辑

   3)并通过注解的方式完成该对象的创建

   4)添加通知的注解配置@Aspect

   5)配置不同类型的通知,在增强的类中,在作为通知方法上面增加通知类型注解,使用切入点表达式配置

        具体代码如下:

package org.learn.spring5.service.impl;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//增强类,编写增强的方法
@Component      //(3)
@Aspect   //(4)
public class UserServiceProxy  {    //(1)

    //前置通知
    @Before(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")   //(5)
    public void before(){
        System.out.println("before");  //(2)
    }
  //后置通知
    @After(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void after(){
    System.out.println("After");
}
    //最终通知
    @AfterReturning(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning");
    }
    //异常通知
    @AfterThrowing(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void afterThrowing(){

        System.out.println("AfterThrowing");
    }
    //环绕通知
    @Around(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕之前");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕之后");
    }
}

 4. 测试类编写:

import org.junit.Test;
import org.learn.spring5.config.SpringConfig;
import org.learn.spring5.service.UserService;
import org.learn.spring5.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring5 {

    /**
     * Spring AOP实现
     */
    @Test
    public void test1(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        userService.add();

    }

}
  • 对公共切入点抽取

例如上面的例子,5种切入点表达式切入的都是同一个方法,表达式都是一样的,那么如何将这行代码抽取成公共的代码进行调用呢?

package org.learn.spring5.service.impl;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//增强类,编写增强的方法
@Component
@Aspect
public class UserServiceProxy {

    //相同的切入点抽取
    @Pointcut(value = "execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void pointCunt(){


    }

    //前置通知
    @Before(value = "pointCunt()")
    public void before(){
    System.out.println("before");
}

    //后置通知
    @After(value = "pointCunt()")
    public void after(){
    System.out.println("After");
}
    //最终通知
    @AfterReturning(value = "pointCunt()")
    public void afterReturning(){
        System.out.println("afterReturning");
    }
    //异常通知
    @AfterThrowing(value = "pointCunt()")
    public void afterThrowing(){

        System.out.println("AfterThrowing");
    }
    //环绕通知
    @Around(value = "pointCunt()")
    public void around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕之前");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕之后");
    }

}
  • 一个方法有多个增强类,设置优先级可以确定执行的顺序

@order()注解,括号里的值越小,优先级越高,先执行

package org.learn.spring5.service.impl;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//增强类2
@Component
@Aspect
@Order(3)
public class UserServiceProxy2 {

    @Before(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))")
    public void before(){
    System.out.println("增强类2 before");
}
}

猜你喜欢

转载自blog.csdn.net/java_cxrs/article/details/108372459