Spring(四:AOP 基于注解)

一、AOP

1. 简介

# 1. 简介
Aspect Oriented Programming:  面向切面编程
在不改变源码的基础上,实现对原有代码的增强

# 2. 术语
连接点:      类中可以被增强的方法
切入点:      类中实际被增强的方法    
通知:        实际增强的额外逻辑部分称为通知,(前置,后置,环绕,异常,最终通知)
切面:        把通知应用到切入点的过程称为切面

# 3. AspectJ
独立于spring,是一个AOP 的具体实现方法
pom:   aspectjweaver
根据具体的类可以自动切换 JDK代理和CGLib 代理

二、AspectJ实现

1. 主配置类

package com.aop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**1. Spring扫描的包
 * 2. 开启aspectj的代理功能*/
@ComponentScan(basePackages = "com.aop")
@EnableAspectJAutoProxy
public class AOPConfig {
}

2. 业务类

  • 会根据业务类是基于接口还是基于子类,动态切换JDK动态代理还是Cglib动态代理
package com.aop;

import org.springframework.stereotype.Component;

@Component
public class VendorService {

    /**
     * 被前置和后置通知  修饰的方法
     */
    public void work() {
        System.out.println("工作");
    }

    /**
     * 被环绕前和环绕后通知  修饰的方法
     */
    public void sleep() {
        System.out.println("睡觉");
    }

    /**
     * AfterThrowing:
     * 1. 如果这个方法抛出异常,则会调用对应的AfterThrowing方法
     * 2. 如果不抛出异常,则对应的AfterThrowing不会执行
     */
    public void eat() {
        int num = 1 / 0;
        System.out.println("吃饭");
    }

    /**
     * AfterReturning:
     * 1. 方法执行后,可以拿到对应的返回值
     */
    public String play() {
        System.out.println("玩耍");
        return "soccer";
    }
}

3. 通知类

package com.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 1.  Aspect: 表明这个类是通知类
 * 2.  value: 表明具体要对哪个类的拿个方法来执行
 */
@Component
@Aspect
public class AspectProxy {

    /**
     * 1.  前置通知: 在要增强的方法之前执行
     */
    @Before(value = "execution(* com.aop.VendorService.work(..) )")
    public void before() {
        System.out.println("前置工作");
    }

    /**
     * 2.  后置通知: 在要增强的方法之后执行
     */
    @After(value = "execution(* com.aop.VendorService.work(..) )")
    public void after() {
        System.out.println("后置工作");
    }

    /**
     * 3.   环绕通知: 在要增强的方法之后执行
     */
    @Around(value = "execution(* com.aop.VendorService.sleep(..) )")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前工作");
        // 具体的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕后工作");
    }

    /**
     * 4.   异常通知: 对应的方法如果抛出异常,则会先调用这个方法,然后原来异常方法继续执行
     */
    @AfterThrowing(value = "execution(* com.aop.VendorService.eat(..) )")
    public void afterThrowing() {
        System.out.println("抛出错误");
    }

    /**
     * 5.   AfterReturning通知: 在方法之后执行,并会拿到对应的返回值
     */
    @AfterReturning(value = "execution(* com.aop.VendorService.play(..) )", returning = "result")
    public void afterReturning(Object result) {
        System.out.println(result);
        System.out.println("返回结果的后置方法");
    }
}

三、 通知优化

1. 切入点表达式抽取

package com.aop;

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

@Component
@Aspect
public class AspectProxy {

    /**
     * 如果切入点表达式一样,可以进行pointcut抽取为一个方法
     * 然后将该方法引入到对应的通知中的value中
     */
    @Pointcut(value = "execution(* com.aop.VendorService.eat(..) )")
    public void servicePoint() {
    }

    @Before(value = "servicePoint()")
    public void afterEat() {
        System.out.println("吃饭后置工作");
    }

    @After(value = "servicePoint()")
    public void afterPlay() {
        System.out.println("吃饭前工作");
    }
}

2. 通知优先级

package com.aop;

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


/**
 * 如果一个类同时被多个增强类进行aop行为
 * 可以在类上通过Order(int)进行排序
 * 数字越小,优先级越高
 */
@Component
@Aspect
@Order(1)
public class AspectProxy {

    @Before(value = "execution(* com.aop.VendorService.eat(..) )")
    public void afterEat() {
        System.out.println("第一个吃饭前置工作");
    }
}

@Component
@Aspect
@Order(2)
class AspectProxySecond {

    @Before(value = "execution(* com.aop.VendorService.eat(..) )")
    public void afterEat() {
        System.out.println("第二个吃饭前置工作");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值