首页 > 编程语言 >springboot实现AOP切面编程

springboot实现AOP切面编程

时间:2022-12-19 11:38:20浏览次数:52  
标签:springboot 通知 void 切面 AOP execution 方法 public


概述

AOP(Aspect Oriented Programming) 即面向切面编程。面向切面是面向对象中的一种方式而已。在代码执行过程中,动态嵌入其他代码,叫做面向切面编程(将交叉业务逻辑封装成成切面,利用AOP功能将切面织入到主业务逻辑———与主业务逻辑无关的代码,使用场景如:安全检查,事物,日志等 。

AOP是一种方式,实现AOP的库有名的有两个AspectJ和spring AOP.

AOP的相关术语

  • 连接点(JoinPoint) : 连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点(被代理对象的所有方法)
  • 切点(Pointcut): 切入点是指我们要对哪些Joinpoint进行拦截的定义(被代理对象加强的方法)
  • 通知(Advice) : 通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • 目标对象(target): 代理的目标对象, 被通知的对象,也就是真正的业务逻辑;
  • 织入(weaving) : 是指把增强应用到目标对象来创建新的代理对象的过程(生成代理对象的过程)
  • 切面(Aspect) : 是切入点和通知的结合,以后咱们自己来编写和配置的

springboot实现AOP切面编程_AOP

AOP的通知类型

  • 前置通知 : 在目标类的方法执行之前执行。
  • 配置文件信息:<aop: before method=“before” pointcut-ref=“myPointcut3”/>
  • 应用:可以对方法的参数来做校验
  • 最终通知 : 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
  • 在配置文件中编写具体的配置:<aop:after method=“after” pointcut-ref=“myPointcut3”/>
  • 应用:例如像释放资源
  • 后置通知 : 方法正常执行后的通知。
  • 在配置文件中编写具体的配置:<aop:after-returning method=“afterReturning” pointcut-ref=“myPointcut2”/>
  • 应用:可以修改方法的返回值
  • 异常抛出通知 : 在抛出异常后通知
  • 在配置文件中编写具体的配置:<aop:after-throwing method=“afterThorwing” pointcut-ref=“myPointcut3”/>
  • 应用:包装异常的信息
  • 环绕通知: 方法的执行前后执行。环绕通知使用灵活.其他方式都能用环绕方式实现。
  • 在配置文件中编写具体的配置:<aop:around method=“around” pointcut-ref=“myPointcut2”/>
  • 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。

使用aspectj实现AOP功能

在pom.xml中引入依赖:

<!--spring aop + aspectj-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--spring aop + aspectj-->
方式一:
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
//注解表明这是一个AspectJ文件,编译器在编译的时候,就会自动去解析,然后将代码注入到相应的JPonit中。
@Aspect //必须的注解
@Order(-1)
public class AOPDemo {



@Pointcut(value = "execution(* com.controller.update(..))")
private void beforePointcut(){
//切面,方法里的内容不会执行
}
@Before(value = "beforePointcut()")
public void before(JoinPoint joinPoint){
//@Before是在方法执行前无法终止原方法执行
System.out.println("前置通知。。。"+joinPoint);
}


@Pointcut(value = "execution(* com.controller.save(..))")
private void afterReturningPointcut(){}
@AfterReturning(value = "afterReturningPointcut()",returning = "result")
public void afterReturning(Object result){
System.out.println("后置通知。。。"+result);
}




@Pointcut(value = "execution(* com.controller.delete(..))")
private void aroundPointcut(){}
@Around(value = "aroundPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//用@Around用环绕通知可以拒绝可以放行
System.out.println("环绕通知。。。");
Object obj = joinPoint.proceed();
System.out.println("环绕通知。。。");

return obj;
}



@Pointcut(value = "execution(* com.controller.findOne(..))")
private void afterThrowingPointcut(){}
@AfterThrowing(value = "afterThrowingPointcut()",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("异常抛出通知"+e.getMessage());
}




@Pointcut(value = "execution(* com.controller.findAll(..))")
private void afterPointcut(){}
//|| 关联多个切面
@After(value = "afterPointcut() || afterReturningPointcut()")
public void after(){
System.out.println("最终通知");
}


}
  • execution: 处理JPoint的类型,例如call,execution
    例如定义切入点表达式 execution (* com.sample.service.impl…*. *(…)) 整个表达式可以分为五个部分:
    1、execution(): 表达式主体。
    2、第一个*号:表示返回类型, *号表示所有的类型。
    3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
    4、第二个*号:表示类名,*号表示所有的类。
    5、*(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

多个切点例如:
@Before("execution (
android.app.Activity.onCreate(…)) ||execution (* android.app.Activity.onDestroy()) "

JoinPoint 对象

JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:

  • Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类
    Class等信息
  • Object[] getArgs(); 获取传入目标方法的参数对象
  • Object getTarget(); 获取被代理的对象
  • Object getThis(); 获取代理对象

ProceedingJoinPoint对象

ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
添加了

  • Object proceed() throws Throwable //执行目标方法 ,放行进入被代理对象的方法
  • Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
    两个方法.
方式二使用注解:

1.首先,我们需要自定义一个注解类

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
public @interface AopLog {}

2.然后,创建一个切面文件,内部通过一个Pointcut来指定在带有我们上面自定义注解类AopLog注解的所有方法上进行拦截。

@Aspect
public class AopLogPointcut {
//在带有AopLog注解的方法进行切入(注:此处的 * *前面都要有一个空格)
@Pointcut("execution(@com.yn.aspectj.selfmakeaop.AopLog * *(..))")
public void logPointcut(){} //注意,这个函数必须要有实现,否则Java编译器会报错

@After("logPointcut()")
public void onLogPointcutAfter(JoinPoint joinPoint) throws Throwable{
Log.i("AOP","onLogPointcutAfter:"+joinPoint.getSignature());
}
}

3.最后,只需要在要进行切入的函数前加上@AopLog注解即可。
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testAopLog();
}

@AopLog
public void testAopLog() {
Log.i("AOP","in testAopLog");
}
}


标签:springboot,通知,void,切面,AOP,execution,方法,public
From: https://blog.51cto.com/u_10176086/5951807

相关文章