spring AOP

spring AOP

今天我们学习spring的另外的一大核心,AOP,也就是面向切面编程.

简介

Aop关注的不再是程序代码中某个类,某些⽅法,⽽aop考虑的更多的是⼀种⾯到⾯的切⼊,即层与层之间的⼀种切⼊,所以称之为切⾯。

AOP主要应⽤于⽇志记录,性能统计,安全控制,事务处理等⽅⾯,实现公共功能性的重复使⽤。

AOP的底层实现:动态代理(JDK + CGLIB)

特点

  1. 降低模块与模块之间的耦合度,提⾼业务代码的聚合度。(⾼内聚低耦合)
  2. 提⾼了代码的复⽤性。
  3. 提⾼系统的扩展性。(⾼版本兼容低版本)
  4. 可以在不影响原有的功能基础上添加新的功能

AOP基本概念

Joinpoint(连接点):被拦截到的每个点,spring中指被拦截到的每⼀个⽅法

Pointcut(切⼊点):匹配的⽅法集合

Advice(通知):拦截到每⼀个连接点即(每⼀个⽅法)后所要做的操作

​ 前置通知 (前置增强)— before() 执⾏⽅法前通知

​ 返回通知(返回增强)— afterReturn ⽅法正常结束返回后的通知

​ 异常抛出通知(异常抛出增强)— afetrThrow()

​ 最终通知 — after ⽆论⽅法是否发⽣异常,均会执⾏该通知。

​ 环绕通知 — around 包围⼀个连接点(join point)的通知,如⽅法调⽤。

Aspect(切⾯):切⼊点与通知的结合,决定了切⾯的定义

Target(⽬标对象):被代理的⽬标对象

Weave(织⼊):将切⾯应⽤到⽬标对象并⽣成代理对象的这个过程即为织⼊

Introduction(引⼊):在不修改原有应⽤程序代码的情况下,在程序运⾏期为类动态添加⽅法或者字段的过程称为引⼊

Aop 理解

  1. ⾯向切⾯,相⽐oop 关注的是代码中的层 或⾯
  2. 解耦,提⾼系统扩展性
  3. 提⾼代码复⽤

环境搭建

和spring ioc一样我们使用maven-quitstart,基础配置也是一样的

1>坐标依赖引⼊aspectjweaver

2>添加spring.xml的配置

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

AOP的实现

注解实现

配置⽂件(spring.xml)

<!--配置AOP代理-->
<aop:aspectj-autoproxy/>

定义切面
定义切入点:@Pointcut(“匹配规则”)
Aop 切入点表达式简介
1 . 执行任意公共方法:execution(public (…))
2. 执行任意的set方法: execution(
set*(…))
3. 执行com.xxxx.service包下任意类的任意方法
execution(* com.xxxx.service..(…))
4. 执行com.xxxx.service 包 以及子包下任意类的任意方法
execution(* com.xxxx.service….(…))
注:表达式中的第一个* 代表的是方法的修饰范围
可选值:private、protected、public (* 表示所有范围)

@Component
@Aspect
public class UserService {
    /**
     *  切入点:
     *      匹配规则。规定什么方法被拦截、需要处理什么方法
     *  定义切入点
     *    @Pointcut("匹配规则")
     *
     *    Aop 切入点表达式简介
     *       1. 执行任意公共方法:
     *       	execution(public *(..))
     *       2. 执行任意的set方法
     *       	execution(* set*(..))
     *		 3. 执行com.xxxx.service包下任意类的任意方法
     *      	execution(* com.xxxx.service.*.*(..))
     *       4. 执行com.xxxx.service 包 以及子包下任意类的任意方法
     *     		execution(* com.xxxx.service..*.*(..))
     *
     *    	 注:表达式中的第一个* 代表的是方法的修饰范围
     *			可选值:private、protected、public (* 表示所有范围)
     */

    @Pointcut("execution (* com.xxxx.service..*.*(..) )")
    public void cut(){};
    @Before(value="cut()")
    public void Before(){
        System.out.println("前置通知");
    }

    @AfterReturning(value="cut()")
    public void ar(){
        System.out.println("返回通知");
    }
    @AfterThrowing(value="cut()",throwing ="e")
    public void at(Exception e){
        System.out.println("异常通知"+e.getCause());
    }
    @After(value="cut()")
    public void after(){
        System.out.println("最终通知");
    }
}
public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext ap=new ClassPathXmlApplicationContext("spring.xml");
        UserService userService= (UserService) ap.getBean("userService");
        userService.cut();
    }
}

环绕通知

// @Around(value = "cut()")
    public void around(ProceedingJoinPoint pjp){
        //前置通知
        System.out.println("环绕----前置通知");
        try {
            pjp.proceed(); //显示调用,放行 去执行目标方法
            //正常执行  返回通知
            System.out.println("环绕----返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕----异常通知");
        }
        System.out.println("环绕----最终通知");
    }

xml实现

定义切面

/**
 * 切面(XML形式)
 *      切入点和通知组成
 *
 *      切入点
 *          增强哪些方法,使用规则匹配到一批方法
 */
@Service
public class UserAspectXml {


    
    public void cut(){};

    /**
     * 前置通知
     *      方法执行之前执行通知
     */
    public void before(){
        System.out.println("前置通知......方法执行之前执行通知");
    }

    /**
     * 返回通知
     *      方法正常执行完执行的通知
     */
    public void afterReturn(){
        System.out.println("返回通知.....方法正常执行完执行的通知");
    }

    /**
     * 异常通知
     *      方法正常执行完执行的通知
     */
    public void afterThrow(Exception e){
        System.out.println("异常通知......方法执行异常时完执行的通知 "+e.getMessage() );
    }

    /**
     * 最终通知
     *      方法执行结束之后执行的通知 (无论代码是否正常执行)
     */
    public void after(){
        System.out.println("最终通知......方法执行结束之后执行的通知");
    }


    /**
     * 环绕通知
     *      方法执行前后  通过环绕通知定义相应处理
     *      需要通过显式调用对应的方法,否则无法访问指定方法 (pjp.proceed();)
     */
    public void around(ProceedingJoinPoint pjp){
        //前置通知
        System.out.println("环绕----前置通知");
        try {
            pjp.proceed(); //显示调用,放行 去执行目标方法
            //正常执行  返回通知
            System.out.println("环绕----返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕----异常通知");
        }
        System.out.println("环绕----最终通知");
    }
}

配置文件(spring.xml)

<!--xml形式配置AOP-->
    <aop:config>
        <aop:aspect ref="userAspectXml">
            <aop:pointcut id="cut" expression="execution(* com.xxxx.service..*.*(..))"/>
            <aop:before method="before" pointcut-ref="cut" />
            <aop:after method="after" pointcut-ref="cut"></aop:after>
            <aop:after-returning method="afterReturn" pointcut-ref="cut"></aop:after-returning>
            <aop:after-throwing method="afterThrow" pointcut-ref="cut" throwing="e"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="cut"></aop:around>
        </aop:aspect>
    </aop:config>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值