← 返回首页
Spring基础教程(十五)
发表时间:2020-05-16 17:03:07
讲解AspectJ实现AOP

AspectJ 是一个基于 Java 语言的 AOP 框架,它扩展了 Java 语言。Spring 2.0 以后,新增了对 AspectJ 方式的支持,新版本的 Spring 框架,建议使用 AspectJ 方式开发 AOP。

使用 AspectJ 开发 AOP 通常有两种方式: - 基于 XML 的声明式。 - 基于 Annotation 的声明式。

本教程主要以注解开发方式进行讲解。

AspectJ Annotation 常用注解如下表:

名称 说明
@Aspect 用于定义一个切面。
@Pointcut 用于定义一个切入点。
@Before 用于定义前置通知,相当于 BeforeAdvice。
@AfterReturning 用于定义后置通知,相当于 AfterReturningAdvice。
@Around 用于定义环绕通知,相当于MethodInterceptor。
@AfterThrowing 用于定义抛出通知,相当于ThrowAdvice。
@After 用于定义最终final通知,不管是否异常,该通知都会执行。
@DeclareParents 用于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。

实例:

项目结构图如下:

实现步骤

1.在pom.xml添加aop和aspectJ依赖

<?xml version="1.0" encoding="UTF-8"?>
<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.simoniu</groupId>
    <artifactId>springbase</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>5.2.5.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

2.编写学生实体类

package com.entity;

public class Students {

    private String sid; //学号
    private String sname; //姓名
    private String gender; //性别
    private String major; //专业

    public Students() {
    }

    public Students(String sid, String sname, String gender, String major) {
        this.sid = sid;
        this.sname = sname;
        this.gender = gender;
        this.major = major;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    @Override
    public String toString() {
        return "Students{" +
                "sid='" + sid + '\'' +
                ", sname='" + sname + '\'' +
                ", gender='" + gender + '\'' +
                ", major='" + major + '\'' +
                '}';
    }
}

3.定义业务逻辑接口

package com.dao;

public interface BusinessDao<T> {

    public void add(T obj);
    public void query(String identify);
    public void delete(String identify);
    public void update(T obj);
}

4.定义学生业务逻辑接口

package com.dao;
public interface StudentsDao<Students> extends BusinessDao<Students> {

}

5.编写学生业务逻辑实现类

package com.dao.impl;

import com.dao.StudentsDao;
import org.springframework.stereotype.Repository;

@Repository
public class StudentsDaoImpl implements StudentsDao<Students> {

    public void add(Students s) {
        System.out.println("新增学生:"+s);
    }

    public void query(String identify) {
        System.out.println("查询学生编号:" + identify);
    }

    public void delete(String identify) {
        System.out.println("删除学生编号:" + identify);
    }

    public void update(Students s) {
        System.out.println("修改学生:"+s);
    }
}

6.在SpringConfiguration配置类中配置一个Students类型的bean

package com.config;

import com.entity.Students;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration

public class SpringConfiguration {

    @Bean("s1")
    public Students getStudents1(){
        return new Students("S001","张三","男","软件工程");
    }
}

7.定义业务逻辑切面类

package com.aspect;

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

@Component//类注解
@Aspect
public class BusinessAspect {

    //声明公共切入点
    @Pointcut("execution(* com.dao.impl.StudentsDaoImpl.*(..))")
    public void myPointcut() {

    }

    @Before(value = "myPointcut()")
    public void checkPri() {
        System.out.println("权限的校验...");
    }

    @AfterReturning(value="myPointcut()")
    public void logger() {
        System.out.println("日志记录...");
    }


    @AfterThrowing(value="myPointcut()",throwing="e")
    public void afterThrowing(Throwable e) {
        System.out.println("异常抛出通知..."+e.getMessage());
    }

    @After(value="myPointcut()")
    public void after() {
        System.out.println("最终通知...");
    }

    //环绕通知;
    @Around(value="myPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object obj=null;
        try {
            System.out.println("环绕内的前置通知");
            obj = joinPoint.proceed();
            System.out.println("环绕内的后置通知");
        } catch (Throwable e) {
            System.out.println("环绕内的异常抛出通知");
            e.printStackTrace();
        } finally {
            System.out.println("环绕内的最终通知");
        }
        return obj;
    }
}

8.在applicationContext.xml中开启aspectJ注解

由于Spring默认不支持AspectJ注解方式,必须在配置文档中开启AspectJ注解。

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

    <!-- 扫描注解类 -->
    <context:component-scan base-package="com"/>
    <!-- 确定AspectJ注解生效 -->
    <aop:aspectj-autoproxy/>
</beans>

9.编写测试类

package com.test;

import com.dao.StudentsDao;
import com.entity.Students;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAspectDemo {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Students s = (Students) context.getBean("s1");
        StudentsDao studentsDaoImpl = (StudentsDao) context.getBean("studentsDaoImpl");
        System.out.println(s);
        studentsDaoImpl.add(s);
    }
}

运行结果:
Students{sid='S001', sname='张三', gender='男', major='软件工程'}
环绕内的前置通知
权限的校验...
新增学生:Students{sid='S001', sname='张三', gender='男', major='软件工程'}
环绕内的后置通知
环绕内的最终通知
最终通知...
日志记录...

基于注解方式实现以上案例,我们无需配置applicationContext.xml,只需要把SpringConfiguration 配置类改写为如下:

package com.config;

import com.entity.Students;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com") 
@EnableAspectJAutoProxy //表示启用aspectJ
public class SpringConfiguration {

    @Bean("s1")
    public Students getStudents1(){
        return new Students("S001","张三","男","软件工程");
    }
}