SpringBoot基于注解的面向切面编程

一、基础概念

1、切面(Aspect)

面向切面编程则是指,对于一个我们已经封装好的类,我们可以在编译期间或在运行期间,对其进行切割,把立方体切开,在原有的方法里面添加(织入)一些新的代码,对原有的方法代码进行一次增强处理。而那些增强部分的代码,就被称之为切面,常见的有日志处理、事务处理、权限认证等等。

2、切入点(PointCut)

要对哪些类中的哪些方法进行增强,进行切割,指的是被增强的方法。即要切哪些东西。

3、连接点(JoinPoint)

我们知道了要切哪些方法后,剩下的就是什么时候切,在原方法的哪一个执行阶段加入增加代码,这个就是连接点。如方法调用前,方法调用后,发生异常时等等。

4、通知(Advice)

通知被织入方法,该如何被增强。定义切面的具体实现。@Pointcut规则中指明的方法即为切入点,@Before、@After是连接点,而下面的代码就是对应通知。

5、目标对象(Target Object)

被一个或多个切面所通知的对象,即为目标对象。

6、AOP代理对象(AOP Proxy Object)

AOP代理是AOP框架所生成的对象,该对象是目标对象的代理对象。代理对象能够在目标对象的基础上,在相应的连接点上调用通知。

7、织入(Weaving)

将切面切入到目标方法之中,使目标方法得到增强的过程被称之为织入。

二、使用方法

1、引入依赖
	
    
        org.springframework.boot
        spring-boot-starter-aop
    
2、自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 这是一个环绕通知的注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AroundAspect {
}
3、定义切面和切入点
import com.example.demo.aspect.AroundAspect;
import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component //component注解必须要有
public class MyTest {

    @AroundAspect
    public void log(){
        System.out.println("输出日志");
    }
}
4、定义通知
import com.alibaba.fastjson.JSONArray;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 1、定义切入点:对要拦截的方法进行定义与限制,如包、类
 * 2、定义通知:编写通知要执行的代码
 */
@Aspect
@Component //component注解必须要有
public class TestAspect{
	/**
     * 环绕通知
     */
    @Pointcut("@annotation(com.example.demo.aspect.AroundAspect)")
    private void around(){}
    @Around("around()")
    private Object testAop(ProceedingJoinPoint point) throws Throwable {
        System.out.println("======AopAspectJ执行环绕通知开始=========");
        Object obj = point.proceed();
        Object[] args = point.getArgs();
        //方法名
        String methodName = point.getSignature().getName();
        //对象
        Object target = point.getTarget();
        //类名
        String className = target.getClass().getName();
        System.out.println("类:"+className+";方法:"+methodName+";参数:"+ JSONArray.toJSONString(args));
        System.out.println("======AopAspectJ执行环绕通知结束=========");
        return obj;
    }
}
5、测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class AspectTest {

    @Autowired
    MyTest test;

    @Test
    public void before(){
        test.log();
    }
}
6、其他通知方式
	/**
     * 前置通知
     */
    @Pointcut("@annotation(com.example.demo.aspect.BeforeAspect)")
    private void before(){}
    @Before("before()")
    public void beforeAdvance(){
        System.out.println("======AopAspectJ执行前置通知=========");
    }
    
    /**
     * 后置通知(在目标方法执行后调用,若目标方法出现异常,则不执行)
     */
    @Pointcut("@annotation(com.example.demo.aspect.AfterRunningAspect)")
    private void afterRunning(){}
    @AfterReturning("afterRunning()")
    private void afterRunningAdvance(){
        System.out.println("======AopAspectJ执行后置通知=========");
    }

    /**
     * 最终通知(在目标方法执行后调用,无论目标方法是否出现异常,都会执行)
     */
    @Pointcut("@annotation(com.example.demo.aspect.AfterAspect)")
    private void after(){}
    @After("after()")
    public void afterAdvance(){
        System.out.println("======AopAspectJ执行最终通知=========");
    }

    /**
     * 异常通知:目标方法抛出异常时执行
     */
    @Pointcut("@annotation(com.example.demo.aspect.AfterThrowingAspect)")
    private void afterThrowing(){}
    @AfterThrowing("afterThrowing()")
    public void afterThrowingAdvance() {
        System.out.println("======AopAspectJ执行异常通知=========");
    }

注意点:整个过程都是Spring的过程,一定要将对象放在Spring容器中管理

你可能感兴趣的:(SpringBoot,aop)