【Spring5-03】AOP

0、重点掌握内容

  1. AOP概念、底层原理(两种动态代理)
  2. AOP术语
  3. AOP操作(AspectJ注解)

一、AOP概念和底层原理

  1. 什么是AOP?
    (1)面向切面编程(方面),利用AOP对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
    解释:不通过修改源代码方式,在主干功能中添加新的功能
  2. AOP底层使用动态代理
    (1)有两种情况动态代理
    \quad 第一种:有接口情况,使用JDK动态代理。
    \quad > 创建接口实现类的代理对象,增强类的方法

在这里插入图片描述

\quad\quad\quad 第二种:无接口情况,使用CGLIB动态代理。
\quad\quad\quad > 创建子类的代理对象,增强类的方法
在这里插入图片描述

二、AOP(JDK动态代理)

  1. 使用JDK动态代理,使用proxy类里面的方法创建代理对象
    (1)调用newProxyInstance方法

方法有三个参数:
第一个参数:类加载器
第二个参数: 增强方法所在的类,这个类实现的接口,支持多个接口。
第三个参数: 实现这个接口InvocationHandler,创建代理对象,写增强的方法。

  1. 编写JDK动态代理代码
    (1)创建接口,定义方法
public interface UserDao {
    public int add(int a, int b);

    public String update(String id);
}

\quad\quad (2)创建接口实现类,实现方法

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b){
        return a+b;
    }

    @Override
    public String update(String id){
        return id;
    }
}

\quad\quad (3)使用Proxy类创建接口代理类对象

public class JDKProxy {
    public static void main(String[] args) {

        Class[] interfaces = {UserDao.class}; //被代理类所是实现的接口
        UserDaoImpl userDao = new UserDaoImpl(); //代理类对象实现被代理类对象方法及新增方法
        UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
        int result = dao.add(1,2);
        System.out.println(result);
    }
}

//创建代理对象代码
class UserDaoProxy implements InvocationHandler{

    //1. 把创建的是谁的代理对下个,把谁传递进来
    // 有参构造传递

    private Object obj;
    public UserDaoProxy(Object obj){
        this.obj = obj;
    }

    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        //方法之前
        System.out.println("方法之前执行..."+method.getName()+":传递的参数...."+ Arrays.toString(args));

        //被增强的方法执行
        Object res = method.invoke(obj,args);

        //方法之后
        System.out.println("方法之后执行...."+obj);
        return res;
    }
}

三、AOP(术语)

  1. 连接点
    类里面哪些方法可以被增强,这些方法成为连接点。
  2. 切入点
    实际被真正增强的方法,称为切入点。
  3. 通知(增强)
    (1)实际增强的逻辑部分称为通知(增强)
    (2)通知有多种类型
    \quad\quad * 前置通知:@Before
    \quad\quad * 后置通知:@AfterReturning
    \quad\quad * 环绕通知:@Around
    \quad\quad * 异常通知:@AfterThrowing
    \quad\quad * 最终通知:@After
  4. 切面
    是动作,把通知应用到切入点的过程。

四、AOP操作(准备)

  1. Spring 框架一般基于AspectJ实现AOP操作。
    (1)什么是AspectJ?
    *AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作。

  2. 基于AspectJ实现AOP操作
    (1)基于xml配置文件实现
    (2)基于注解方式实现(使用)

  3. 在项目工程里面引入AOP相关依赖
    在这里插入图片描述

  4. 切入点表达式
    (1)切入点表达式作用:知道对那个类里面的哪个方法进行增强。
    (2)语法结构:
    execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
    举例1: 对com.atguigu.dao.BookDao类里面的add进行增强。
    execution(*com.atguigu.dao.BookDao.add(…))
    星号表示可以是任意修饰符,返回类型可不写。
    举例2: 对com.atguigu.dao.BookDao类里面的所有方法进行增强。
    execution(*com.atguigu.dao.BookDao.*(…))
    星号表示可以是任意修饰符,返回类型可不写。
    举例3: 对com.atguigu.dao里的所有类,类里面的所有方法进行增强。
    execution(*com.atguigu.dao.*.*(…))
    星号表示可以是任意修饰符,返回类型可不写。

五、AOP操作(AspectJ注解)

  1. 创建类,在类里面定义方法
public class User {
    public void add(){
        System.out.println("add.......");
    }
}
  1. 创建增强类(编写增强逻辑)
    (1)在增强类里面,创建方法,让不同方法代表不同通知类型。
//增强的类
public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("before.......");
    }
}
  1. 进行通知的配置
    (1)在Spring配置文件中,开启注解扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启注解扫描-->
    <context:component-scan base-package="cn.dhu.spring5.aopanno"></context:component-scan>

(2)使用注解创建User和UserProxy对象
在这里插入图片描述
在这里插入图片描述

(3)在增强类上面添加注解 @Aspect
在这里插入图片描述
(4)在spring配置文件中开启生成代理对象(也可以改成完全注解开发

<!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 配置不同类型的通知
    (1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式。
//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {
    //前置通知
    //@Before注解表示作为前置通知
    @Before(value="execution(* cn.dhu.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("before.......");
    }
}

  • 注1:Spring AOP 报错org.springframework.beans.factory.BeanCreationException:error creating bean…
    错误原因:
    1、注入bean失败。主要包括未扫描对应包,对应bean未添加注解等;
    2、错误使用excution
    3、AspectJ版本冲突。
    进一步查看报错信息,发现:Could not initialize class org.aspectj.util.LangUtil
    发现是自己jdk版本过高,导致AspectJ版本不兼容问题,故更改jdk版本,解决方法见注2
  • 注2:java: 无效的标记: --add-modules错误
    错误原因:更改jdk版本时,每个模块的编译参数未删除。
    解决:解决 idea 项目中Error:java: 无效的标记
  1. 相同切入点抽取
    //相同切入点抽取
    @Pointcut(value="execution(* cn.dhu.spring5.aopanno.User.add(..))")
    public void pointdemo(){}

    //前置通知
    //@Before注解表示作为前置通知
    @Before(value="pointdemo()")
    public void before(){
        System.out.println("before.......");
    }
  1. 有多个增强类对同一个方法进行增强,设置增强类的优先级
    (1)在增强类上面添加注解@Order(数字类型的值),数字越小优先级越高。
@Component
@Aspect
@Order(1)
public class PersonProxy {

    //相同切入点抽取
    @Pointcut(value="execution(* cn.dhu.spring5.aopanno.User.add(..))")
    public void pointdemo(){}

    //后置通知(返回通知)
    @Before(value="pointdemo()")
    public void before(){
        System.out.println("person before.......");
    }
}
  1. 完全使用注解开发
    (1)创建配置类,不需要创建xml配置文件
@Configuration
@ComponentScan(basePackages={"cn.dhu.spring5"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop{}

//调用时只需要使用以下方法
//ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);

六、AOP操作(AspectJ xml配置文件)

  1. 实际工作中使用注解方式
  2. 创建两个类,增强类和被增强类,创建方法
  3. 在spring配置文件中创建两个类对象
	<!--创建对象-->
    <bean id="book" class="cn.dhu.spring5.aopxml.Book"></bean>
    <bean id="bookProxy" class="cn.dhu.spring5.aopxml.BookProxy"></bean>
  1. 在spring配置文件中配置切入点
    <!--配置aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* cn.dhu.spring5.aopxml.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

参考:本篇内容主要为尚硅谷Spring5听课笔记

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值