Spring AOP具体实现

认识一下AOP

学习Spring的时候,我们都知道其两大特性一个是IOC,一个是AOP,中文名称分别为控制反转和面向切面。控制反转的含义我们大致能理解,面向切面比较抽象,只听说过面向对象OOP,AOP的作用是什么呢?
引文12 3进行了详细的理论和实践解释,本文主要通过引文中的内容,完成从项目创建到AOP实现测试整个过程,可参看参考文献后,再具体的查看本文的完整实现代码。

构建Springboot项目工程

进入https://start.spring.io/,选择项目所需的jar,主要选择Aspects,官方给出的解释是Create your own Aspects using Spring Aop and AspectJ.可以使用Spring AOP或者 AspectJ创建我们自己的切面程序。
然后打包下载。

下载完成后的项目直接用IDEA打开即可。

编写基础功能代码

由于是测试,不再书写DAO,只编写Service,将Spring变成Java命令行程序,然后直观的记录AOP的使用过程。
假设整个系统学生管理系统,我们编写提供学生信息查询的方法。
学生类:

package zmqc.iceyung.bean;
public class Student {

    private int id;

    private int age;

    private String name;

    private String sex;

    public Student(){}

    public Student(int id,int age,String name,String sex){
        this.id = id;
        this.age = age;
        this.name = name;
        this.sex = sex;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

service:

//************************************************service接口
package zmqc.iceyung.service;

import zmqc.iceyung.bean.Student;

import java.util.List;

public interface IStudentService {
    List<Student> getAllStudents();
}
//************************************************service实现类
package zmqc.iceyung.service;

import org.springframework.stereotype.Service;
import zmqc.iceyung.annotation.MyAop;
import zmqc.iceyung.bean.Student;
import java.util.ArrayList;
import java.util.List;


@Service
public class StudentService implements IStudentService{
    @Override
    public List<Student> getAllStudents() {
        Student stu1 = new Student(1,20,"小明","男");
        Student stu2 = new Student(1,18,"小红","女");
        List<Student> list = new ArrayList<>();
        list.add(stu1);
        list.add(stu2);
        return list;
    }
}

主类,实现CommandLineRunner接口,此时的Springboot就不再是web项目,而是java命令行项目:

package zmqc.iceyung;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import zmqc.iceyung.service.IStudentService;
@EnableAspectJAutoProxy
@SpringBootApplication
public class IceyungApplication implements CommandLineRunner{

	@Autowired
	private IStudentService studentService;

	@Override
	public void run(String... args) throws Exception {
		System.out.println(studentService.getAllStudents());
	}
	
	public static void main(String[] args) {
		SpringApplication.run(IceyungApplication.class, args);
	}
}

运行时,显示:
[Student{id=1, age=20, name=‘小明’, sex=‘男’}, Student{id=1, age=18, name=‘小红’, sex=‘女’}]

添加自定义注解,并编写自己的AOP程序

编写自己的AOP程序,AOP程序的拦截是基于切点的,即下面的@Pointcut("@within(zmqc.iceyung.annotation.MyAop)"),该部分为切入点表达式,关于Spring中实现AOP的方式,和切点表达式可以参看引文12 4
具体实现如下:

package zmqc.iceyung.aspects;

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

//切面
@Component
@Aspect
public class MyAop1 implements Ordered {
    //切点,内部为切入点表达式
    @Pointcut("@within(zmqc.iceyung.annotation.MyAop)")
    private void pointCutMethod() {
    }

    //声明前置通知
    @Before("pointCutMethod()")
    public void doBefore(JoinPoint point) {
        System.out.println("doBefore");
        return;
    }

    //声明后置通知
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point,Object returnValue) {
        System.out.println("doAfterReturning");
    }

    //声明例外通知
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println("doAfterThrowing");
    }

    //声明最终通知
    @After("pointCutMethod()")
    public void doAfter() {
        System.out.println("doAfter");
    }

    //声明环绕通知
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object obj = pjp.proceed();

        System.out.println("doAround");
        return obj;
    }


    @Override
    public int getOrder() {
        return 1;
    }
}

上述切点表达式代表了该AOP程序需要拦截的是注解MyAop,所以需要我们自定义注解,可参见引文5

package zmqc.iceyung.annotation;
import java.lang.annotation.*;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAop {
    String value();
}

当添加完我们需要的AOP程序后,在service方法中添加注解@MyAop,如下:

@MyAop("获得全部的学生信息")
    @Override
    public List<Student> getAllStudents() {
        Student stu1 = new Student(1,20,"小明","男");
        Student stu2 = new Student(1,18,"小红","女");
        List<Student> list = new ArrayList<>();
        list.add(stu1);
        list.add(stu2);
        return list;
    }

此时再运行程序,打印结果如下:

doBefore
doAround
doAfter
doAfterReturning
[Student{id=1, age=20, name='小明', sex='男'}, Student{id=1, age=18, name='小红', sex='女'}]

注意:若将@MyAop放在类上,则此时的切点表达式应该是@within,具体看参考引文4

总结什么是AOP

AOP并不是通过繁琐的重复编码来完成非核心的一类问题,而是采用代理等方式,在需要添加管理类时通过类代理的模式进行,让整个的实现过程更加的方便快捷。常见的有日志系统、权限系统、事务等。

项目在线地址:https://gitee.com/iceyung/SpringAOPDemo.git


  1. SpringAOP的应用实例与总结,https://www.cnblogs.com/boywwj/p/7502185.html ↩︎ ↩︎

  2. spring多个AOP执行先后顺序,https://blog.csdn.net/qqxhwwqwq/article/details/51678595 ↩︎ ↩︎

  3. 关于 Spring AOP (AspectJ), 你该知晓的一切https://blog.csdn.net/javazejian/article/details/56267036/ ↩︎

  4. Spring AOP 所有切入点指示符详解(execution,within,this,target,args,@within,@target,@args,@annotation),https://blog.csdn.net/qq_23167527/article/details/78623639 ↩︎ ↩︎

  5. springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)https://www.cnblogs.com/wenjunwei/p/9639909.html ↩︎

发布了89 篇原创文章 · 获赞 28 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/iceyung/article/details/88559341