天天看点

11-spring注解方式实现AOP

步骤:

  1. 导入相应的依赖
  2. 开启注解扫描
  3. 编写代理接口
  4. 被代理接口实现类
  5. 编写切面类
  6. 测试

1. pom.xml加载依赖

<?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>org.example</groupId>
    <artifactId>spring-11</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <!--导入AOP包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>org.aopalliance</groupId>
            <artifactId>com.springsource.org.aopalliance</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
           

需要的依赖:

  1. com.springsource.net.sf.cglib-2.1.3.jar
  2. com.springsource.org.aopalliance-1.0.0.jar
  3. com.springsource.org.aspectj.weaver-1.9.6.RELEASE.jar
  4. spring-aspects-5.2.13.RELEASE

2.spring配置文件

<?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
       http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.qwy"/>
    <!--开启注解的AOP实现-->
    <aop:aspectj-autoproxy/>
</beans>
           
  1. content命名空间
  2. aop命名空间

3. POJO

package com.qwy.bean;

/**
 * @author qwy
 * @create 2021-04-24 9:46
 **/
public class Users {
}

           

此类纯属为了模拟开发

4.代理接口

package com.qwy.servce;

import com.qwy.bean.Users;

/**
 * @author qwy
 * @create 2021-04-24 9:46
 **/
public interface UsersService {
    public void save(Users users);
    public void update(Users users);
    public void deleteById(Integer id);
    public Users getUsersById(Integer id);
}

           

5. 代理接口实现类(被代理对象)

package com.qwy.servce.impl;

import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.springframework.stereotype.Service;

/**
 * @author qwy
 * @create 2021-04-24 9:47
 **/
@Service("usersService")
public class UsersServiceImpl implements UsersService {
    public void save(Users users) {
        System.out.println("UsersServiceImpl.save");
    }

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

    public void deleteById(Integer id) {
        System.out.println("UsersServiceImpl.deleteById");
    }

    public Users getUsersById(Integer id) {
        System.out.println("UsersServiceImpl.getUsersById");
        return new Users();
    }
}

           

只是为了演示AOP,跟业务无参,这里只做了打印,看效果。

  1. @Service :将被代理对象交给Spring容器管理。

6.切面类

package com.qwy.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author qwy
 * @create 2021-04-24 9:29
 **/
@Component
@Aspect
public class LogAspect {
    @Pointcut("execution(* com.qwy.servce.impl.UsersServiceImpl.update(..))")
    private void anyMethod(){}
    @Before("anyMethod()")
    public void beforeMethod(JoinPoint joinPoint){
        //获取被代理对象的方法名
        String name = joinPoint.getSignature().getName();
        //获取被代理对象的参数列表
        Object[] args = joinPoint.getArgs();
        System.out.println("前置通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
    }
    @AfterReturning(value = "anyMethod()",returning = "result")
    public void afterReturnMethod(JoinPoint joinPoint,Object result){
        //获取被代理对象的方法名
        String name = joinPoint.getSignature().getName();
        //获取被代理对象的参数列表
        Object[] args = joinPoint.getArgs();
        System.out.println("返回通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
    }
    @AfterThrowing(value = "anyMethod()",throwing = "e")
    public void afterThrowMethod(JoinPoint joinPoint, Exception e){
        //获取被代理对象的方法名
        String name = joinPoint.getSignature().getName();
        //获取被代理对象的参数列表
        Object[] args = joinPoint.getArgs();
        System.out.println("异常通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
    }

    @After("anyMethod()")
    public void after(JoinPoint joinPoint){
        //获取被代理对象的方法名
        String name = joinPoint.getSignature().getName();
        //获取被代理对象的参数列表
        Object[] args = joinPoint.getArgs();
        System.out.println("后置通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
    }
    //@Around("anyMethod()")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed=null;
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        try{
            //前置通知

            System.out.println("前置通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
            proceed = joinPoint.proceed();
            //返回通知
            System.out.println("返回通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
        }catch (Exception e){
            System.out.println("异常通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
            e.printStackTrace();
        }finally {
            System.out.println("后置通知:  被代理对象的方法:  " + name +" , 参数 :" + args);
        }

        return proceed;
    }

}


           

说明:

  1. @Component :切面必须是 IOC 中的 bean
  2. @Aspect :表名该类为切面类
  3. @Pointcut :定义切面表达式,格式:execution(访问修饰 返回值 类的全名称.方法名(参数列表))
  4. @Before(“anyMethod()”) :表示前置通知,接口的每一个实现类的每一个方法开始之前执行一段代码,anyMethod表示引用@Pointcut定 义的表达式,当然可以单独定义。
  5. @AfterReturning(value = “anyMethod()”,returning = “result”): 表示返回通知是可以访问到方法的返回值的!
  6. @AfterThrowing(value = “anyMethod()”,throwing = “e”):在目标方法出现异常时会执行的代码.可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码。
  7. @After(“anyMethod()”):在方法执行之后执行的代码. 无论该方法是否出现异常
  8. @Around(“anyMethod()”):环绕通知需要携带 ProceedingJoinPoint 类型的参数.环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.且环绕通知必须有返回值, 返回值即为目标方法的返回值。

7. 测试类

package com.qwy.test;

import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author qwy
 * @create 2021-04-24 9:49
 **/
public class TestAnnotationAOP {
    private ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        UsersService usersService = ac.getBean("usersService", UsersService.class);
        usersService.save(new Users());
        usersService.update(new Users());
        usersService.deleteById(1);
        usersService.getUsersById(1);
    }
}

           

执行结果:

UsersServiceImpl.save

前置通知: 被代理对象的方法: update , 参数 :[Ljava.lang.Object;@3c947bc5

UsersServiceImpl.update

返回通知: 被代理对象的方法: update , 参数 :[Ljava.lang.Object;@3c947bc5

后置通知: 被代理对象的方法: update , 参数 :[Ljava.lang.Object;@3c947bc5

UsersServiceImpl.deleteById

UsersServiceImpl.getUsersById

需要演示的结果过多。这里没有分开演示,大家可以分别演示。

继续阅读