Spring学习-2(AOP)

1、什么是AOP

        AOP(Aspect Oriented Programming)面向切面编程,一种编程范式。在不改动原始设计的基础上进行功能增强。

2、AOP的核心概念

(1)连接点:连接点就是可进行功能增强的方法。下列几个方法就是连接点。

 public void select(){
        System.out.println("userDao select...");
    }

    public void delete(){
        System.out.println("userDao delete...");
    }

    public void save(){
        System.out.println("userDao save...");
    }

    public void update(){
        System.out.println("userDao update...");
    }

 (2)切入点:切入点就是需要进行功能增强的方法。比如在上述连接点中只对select方法和delete方法进行增强,那么这两个方法就是切入点。

 public void select(){
        System.out.println("userDao select...");
    }

    public void delete(){
        System.out.println("userDao delete...");
    }

(3)通知:通知是指进行功能增强的代码,假设上述切入点需要使用enhance方法进行增强,那么enhance就是一个通知。

public void enhance(){
        System.out.println("我是增强功能");
    }

(4)切面:在确定切入点和通知后,需要将切入点和通知进行绑定,以确保对对应的方法进行增强,那么这种进行切入点和通知绑定的操作就是切面。

3、AOP的基本使用

(1)导入依赖坐标

spring依赖包中含有aop的依赖包,但还需要额外导入一个aspectjweaver依赖包。

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

(2)定义连接点

package com.example.dao;

import org.springframework.stereotype.Component;

@Component
public class UserDao {
    public void select(){
        System.out.println("userDao select...");
    }

    public void delete(){
        System.out.println("userDao delete...");
    }

    public void save(){
        System.out.println("userDao save...");
    }

    public void update(){
        System.out.println("userDao update...");
    }
    
}

(3)创建通知

package com.example.aop;

public class MyAOP {
    public void enhance(){
        System.out.println("enhance running...");
    }
}

(4)定义切入点

package com.example.aop;

import org.aspectj.lang.annotation.Pointcut;

public class MyAOP {
    
    @Pointcut("execution(void com.example.dao.UserDao.select())")
    private void pt(){}
    
    public void enhance(){
        System.out.println("enhance running...");
    }
}

(5)绑定切入点和通知

package com.example.aop;

import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

public class MyAOP {

    @Pointcut("execution(void com.example.dao.UserDao.select())")
    private void pt(){}

    @Before("pt()")
    public void enhance(){
        System.out.println("enhance running...");
    }
}

(6)将AOP类定义成bean交给Spring管理并告知Spring此类为AOP类

package com.example.aop;

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 MyAOP {

    @Pointcut("execution(void com.example.dao.UserDao.select())")
    private void pt(){}

    @Before("pt()")
    public void enhance(){
        System.out.println("enhance running...");
    }
}

(7)开启Spring对AOP注解驱动支持

package com.example.config;

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

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class SpringConfig {
}

4、AOP切入点表达式

execution(public void com.example.dao.UserDao.select(int))

使用通配符:

(1)* :匹配任意字符

// 匹配所有以 "get" 开头的方法
@Before("execution(* get*(..))")

// 匹配 com.example.service 包下的所有类的所有方法
@Before("execution(* com.example.service.*.*(..))")

// 匹配 UserService 类中的所有方法
@Before("execution(* com.example.service.UserService.*(..))")

(2).. :匹配任意层级的子包或任意参数,该通配符不能单独使用。

// 匹配 com.example 包及其子包下的所有类的所有方法
@Before("execution(* com.example..*.*(..))")

// 匹配所有方法,不管参数是什么
@Before("execution(* *(..))")

// 匹配第一个参数是 String,后面可以有任意参数的方法
@Before("execution(* *(String, ..))")

(3)+ :匹配子类或实现类

// 匹配 UserDao 接口的所有实现类的方法
@Before("execution(* com.example.dao.UserDao+.*(..))")

// 匹配 Repository 注解的所有子类
@Before("execution(* (@org.springframework.stereotype.Repository +).*(..))")

5、AOP通知类型

(1)原始方法执行前

    @Before("pt1()")
    public void beforeEnhance(){
        System.out.println("beforeEnhance running...");
    }

(2)原始方法执行后

    @After("pt2()")
    public void afterEnhance(){
        System.out.println("beforeEnhance running...");
    }

(3)环绕执行方法

        其中pjp.proceed()表示原始方法的执行。

    @Around("pt3()")
    public void aroundEnhance(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before running...");
        pjp.proceed();
        System.out.println("around after running...");
    }

        若原始方法有返回值,则增强方法也需定义对应的返回值,并在调用原始方法后,经过增强的原始方法返回值为增强方法的返回值。例如原始方法返回值为100,增强方法返回值为200,调用原始方法后得到的值为200。

    @Around("pt4()")
    public int aroundEnhanceReturn(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before running...");
        pjp.proceed();
        System.out.println("around after running...");
        return 200;
    }

        若要返回同原始方法一样的返回值,则需使用Oject对象接收pjp.proceed()的返回值,并将接到的返回值返回。

    @Around("pt4()")
    public Object aroundEnhanceReturn(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before running...");
        Object ob = pjp.proceed();
        System.out.println("around after running...");
        return ob;
    }

6、AOP获取参数

        使用JoinPoint接口的getArgs()方法获取原始方法的参数,该接口是ProceedingJoinPoint接口的父接口,所以ProceedingJoinPoint也可以调用getArgs()方法获取原始方法的参数。

    @Before("pt1()")
    public void beforeEnhance(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println(args.toString());
        System.out.println("beforeEnhance running...");
    }

7、AOP原始方法执行后获取原始方法的返回值

        returning的值须与Object类型的变量值一致。若有JoinPoint参数,,则JoinPoint必须在方法参数第一位置。

    @AfterReturning(value = "pt2()",returning = "obj")
    public void afterEnhance(Object obj){
        System.out.println("afterEnhance running..."+obj);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值