【浅学Spring框架--AOP】

在前面的文章中已经学习了IOC的有关知识,接下来就要学习spring框架的另一个重要的部分AOP。


一、AOP的概念

Aspect Oriented Programming 面向切面编程,是一种利用“横切”的技术(底层实现就是动态代理),对原有的业务逻辑进行拦截,并且可以在这个拦截的横切面上添加特定的业务逻辑,对原有的业务进行增强。

解释:其实在我看来,aop技术就是一个将业务代码中一些不重要的内容但是又是有需要的且大量存在各种类或者接口中的信息(例如:日志,验证参数等)进行归类,写道一个类中,然后其他类直接调用这个类里的方法即可
图解:

1.正常处理方式

在这里插入图片描述

2.AOP处理方式

在这里插入图片描述

二、AOP示例

需求说明:BookDaoImpl里面有2个方法save()和update(),但是save方法里面有输出当前时间戳的功能,而update里没有。现需要通过aop使update方法中不添加任何代码,实现输出时间戳的功能。
项目目录图:
在这里插入图片描述

1.导入依赖

1、在pom.xml添加Spring依赖

  • context
  • aspects
 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.20</version>
        </dependency>
        //里面应该还要引入一个aop的依赖,但是点开spring-context里会发现包含了aop依赖所以不用再导入了
<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
  1. Spring配置文件
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.创建一个AOP切面类,只要在类上加个 @Aspect 注解即可。

  • @Aspect 注解用来描述一个切面类,定义切面类的时候需要打上这个注解。
  • @Component 注解将该类交给 Spring 来管理。
package com.etime;

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

@Component//spring控制
@Aspect//说明这是一个切面
public class MyAdvice {

    //哪些方法可以使用--具体使用后面会叙述
    @Pointcut("execution(void com.etime.dao.impl.BookDaoImpl.update())")
    private void pt(){}

    //与上面的绑定
    @Before("pt()") //具体含有后面会叙述
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

4.其他类的内容:

package com.etime.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
//SpringConfig配置类
@Configuration
@ComponentScan("com.etime")
@EnableAspectJAutoProxy//spring中有注解开发的aop
public class SpringConfig {
}

package com.etime.dao.impl;
//BookDao接口
public interface BookDao {
    public void save();
    public void update();
}

package com.etime.dao.impl;
import org.springframework.stereotype.Repository;
//BookDaoImpl 实现类
@Repository 
public class BookDaoImpl implements BookDao{
    @Override
    public void save() {
        System.out.println(System.currentTimeMillis());
        System.out.println("book is save...");
    }

    @Override
    public void update() {
        System.out.println("book is update...");
    }
}

package com.etime.Test;

import com.etime.config.SpringConfig;
import com.etime.dao.impl.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
//App测试类
public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = ctx.getBean(BookDao.class);
        bookDao.update();
    }
}

5.运行结果:
在这里插入图片描述

2.AOP的有关注解

有很多人肯定很不能理解切面类里@Pointcut(“execution(void com.etime.dao.impl.BookDaoImpl.update())”),以及before等注解的作用,下面将对aop的部分注解进行介绍。

2.1 @Pointcut

@Pointcut 注解指定一个切点,定义需要拦截的东西,这里介绍两个常用的表达式:一个是使用 execution(),另一个是使用 annotation()。

execution表达式
在这里插入图片描述

annotation() 表达式:
annotation() 方式是针对某个注解来定义切点,比如我们对具有 @PostMapping 注解的方法做切面,可以如下定义切面:
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") public void annotationPointcut() {}
然后使用该切面的话,就会切入注解是 @PostMapping 的所有方法。这种方式很适合处理 @GetMapping、@PostMapping、@DeleteMapping不同注解有各种特定处理逻辑的场景。

2.2 @Before

@Before: 注解指定的方法在切面切入目标方法之前执行。

2.3 @After

@After:注解指定的方法在切面切入目标方法之后执行。

2.4 @AfterReturning

@AfterReturning: 返回通知, 在方法返回结果之后执行。

2.5 @AfterThrowing

@AfterThrowing: 异常通知, 在方法抛出异常之后。

2.6 @Around(重点)

@Around: 环绕通知, 围绕着方法执行。

四种通知的执行顺序。以动态代理方式的位置来进行说明:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
//@Before
result = method.invoke(target, args);
//@AfterReturning
return result;
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
//@AfterThrowing
throw targetException;
} finally {
//@After
}
}
  • 2.6.1 处理能力强,功能多,表现在:

1.@Around可以自由选择增强动作与目标方法的执行顺序,也就是说可以在增强动作前后,甚至过程中执行目标方法。这个特性的实现在于,调用ProceedingJoinPoint参数的procedd()方法才会执行目标方法。
2.@Around可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值。

  • Around增强处理有以下特点:

1.当定义一个Around增强处理方法时,该方法的第一个形参必须是 ProceedingJoinPoint 类型(至少一个形参)。在增强处理方法体内,调用ProceedingJoinPoint的proceed方法才会执行目标方法:这就是@Around增强处理可以完全控制目标方法执行时机、如何执行的关键;如果程序没有调用ProceedingJoinPoint的proceed方法,则目标方法不会执行。
2.调用ProceedingJoinPoint的proceed方法时,还可以传入一个Object[ ]对象,该数组中的值将被传入目标方法作为实参——这就是Around增强处理方法可以改变目标方法参数值的关键。这就是如果传入的Object[ ]数组长度与目标方法所需要的参数个数不相等,或者Object[ ]数组元素与目标方法所需参数的类型不匹配,程序就会出现异常。

@Component
@Aspect
public class OperationAspectAround {
@Around("execution(* *.oper(..))")
public Object around(ProceedingJoinPoint point){
System.out.println("before....");
Object obj = null;
try{
obj = point.proceed();
System.out.println("after return...");
}catch(Throwable e){
System.out.println("Throwable..");
}finally{
System.out.println("after....");
}
return obj;

总结

以上所关于AOP的有关内容,内容很多,上面也仅仅是写出了我所学习的,自己查阅资料了解到的内容。关于Spring框架的内容后面文章会继续介绍。
注意:此文章为学习记录文章,参考多篇文章,如有不正之处请指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值