Spring AOP理解及应用(附含自定义注解使用)

概念

  • 通知(Advice)

切面的工作被称为通知。通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。
5种通知类型:

  1. 前置通知(Before):在目标方法被调用之前调用通知功能
  2. 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
  3. 返回通知(After-returning):在目标方法成功执行之后调用通知
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知
  5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和之后执行自定义的行为
    后置通知和返回通知的区别是,后置通知是不管方法是否有异常,都会执行该通知;而返回通知是方法正常结束时才会执行。
  • 连接点(Join point)

连接点是在应用执行过程中能够插入切面的一个点。

  • 切点(Pointcut)

一个切面并不需要通知应用的所有连接点,切点有助于缩小切面所通知的连接点范围。如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”。因此,切点其实就是定义了需要执行在哪些连接点上执行通知。

  • 切面(Aspect)

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和在何处完成其功能。

  • 引入(Introduction)

引入允许我们向现有的类添加新方法或属性。

  • 织入(Weaving)

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有很多个点可以进行织入:

  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
  • 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ
    5的加载时织入就支持这种方式织入切面。
  • 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态的创建一个代理对象。Spring
    AOP就是以这种方式织入切面的。

应用

spring AOP自定义注解方式实现日志管理

  • 第一,注解:

@Before – 目标方法执行前执行

@After – 目标方法执行后执行

@AfterReturning – 目标方法返回后执行,如果发生异常不执行

@AfterThrowing – 异常时执行

@Around – 在执行上面其他操作的同时也执行这个方法

  • 第二,SpringMVC如果要使用AOP注解,必须将
<aop:aspectj-autoproxy proxy-target-class="true"/>

放在spring-servlet.xml(配置MVC的XML)中

  • 三、通过切点来选择连接点

以下是Spring AOP所支持的AspectJ切点指示器

arg() 限制连接点匹配参数为指定类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的bean引用为指定类型的类
target 限制连接点匹配目标对象为指定类型的类
@target 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里)
@annotation 限定匹配带有指定注解的连接点
在这里插入图片描述

自定义注解声明

package org.xdemo.example.springaop.annotation;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Log {
    String name() default "";
}

利用AOP实现自定义注解

package org.xdemo.example.springaop.aop;
 
import java.lang.reflect.Method;
import java.util.UUID;
 
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.xdemo.example.springaop.annotation.Log;
 
@Aspect
@Component
public class LogAop_2 {
 
    ThreadLocal<Long> time=new ThreadLocal<Long>();
    ThreadLocal<String> tag=new ThreadLocal<String>();
     
    @Pointcut("@annotation(org.xdemo.example.springaop.annotation.Log)")
    public void log(){
        System.out.println("我是一个切入点");
    }
     
    /**
     * 在所有标注@Log的地方切入
     * @param joinPoint
     */
    @Before("log()")
    public void beforeExec(JoinPoint joinPoint){
         
        time.set(System.currentTimeMillis());
        tag.set(UUID.randomUUID().toString());
         
        info(joinPoint);
         
        MethodSignature ms=(MethodSignature) joinPoint.getSignature();
        Method method=ms.getMethod();
        System.out.println(method.getAnnotation(Log.class).name()+"标记"+tag.get());
    }
     
    @After("log()")
    public void afterExec(JoinPoint joinPoint){
        MethodSignature ms=(MethodSignature) joinPoint.getSignature();
        Method method=ms.getMethod();
        System.out.println("标记为"+tag.get()+"的方法"+method.getName()+"运行消耗"+(System.currentTimeMillis()-time.get())+"ms");
    }
     
    @Around("log()")
    public void aroundExec(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("我是Around,来打酱油的");
        pjp.proceed();
    }
     
    private void info(JoinPoint joinPoint){
        System.out.println("--------------------------------------------------");
        System.out.println("King:\t"+joinPoint.getKind());
        System.out.println("Target:\t"+joinPoint.getTarget().toString());
        Object[] os=joinPoint.getArgs();
        System.out.println("Args:");
        for(int i=0;i<os.length;i++){
            System.out.println("\t==>参数["+i+"]:\t"+os[i].toString());
        }
        System.out.println("Signature:\t"+joinPoint.getSignature());
        System.out.println("SourceLocation:\t"+joinPoint.getSourceLocation());
        System.out.println("StaticPart:\t"+joinPoint.getStaticPart());
        System.out.println("--------------------------------------------------");
    }
     
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值