尚硅谷Spring笔记: AOP

AOP

概念

什么是AOP

(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

(3)使用登录例子说明AOP

在这里插入图片描述

AOP(底层原理)

  • AOP底层使用动态代理

    (1)有两种情况动态代理

    第一种 有接口情况, 使用JDK动态代理 : 创建接口实现类代理对象,增强类的方法

在这里插入图片描述

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

  • AOP(JDK动态代理)

    1.使用JDK动态代理,使用Proxy类里面的方法来创建代理对象

    (1)调用Proxy类中的newProxyInstance方法
    在这里插入图片描述

    方法有三个参数:

    第一参数: 类加载器

    第二参数: 增强方法所在的类,这个类实现的接口,支持多个接口

    第三参数: 实现这个接口InvocationHandler,创建代理对象,写增强的部分

    2.编写JDK动态代理代码

    (1)创建接口,定义方法

    public interface UserDao {
        public int add(int a,int b);
        
        public String update(String id);
        
    }
    

    (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;
        }
    }
    

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

    public class JDKProxy {
        public static void main(String[] args) {
            //创建接口实现类代理对象
            Class[] interfaces = {UserDao.class};
    
    //        方式1:直接用匿名内部类实现InvocationHandler接口
    //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        })
    
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao =(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int addResult = dao.add(1, 2);
            System.out.println(addResult);
    
        }
    }
    
    
    //方式2:创建一个类实现InvocationHandler接口
    class UserDaoProxy implements InvocationHandler{
        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)通知有多种类型:

    前置通知: 方法之前的执行

    后置通知: 方法之后的执行

    环绕通知: 方法的前后都有执行

    异常通知: 方法出现异常的执行

    最终通知: finally块中的执行

    4.切面 : 是动作,把通知应用到切入点的过程

  • AOP操作(准备)

    1.Spring框架一般基于AsepectJ实现AOP操作

    (1)什么是Asepectj

    AspectJ不是Spring组成部分,独立的AOP框架,一般把AspectJ 和 Spring框架一起使用,进行AOP操作

    2.基于AsepectJ实现AOP操作

    (1)基于xml配置文件实现

    (2)基于注解方式实现(一般使用这种方式)

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

在这里插入图片描述

4.切入表达式

(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

(2)语法结构:

execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))

举例1 : 对com.yzy.dao.BookDao类里面的add()方法进行增强

*表示任意的返回类型

权限修饰符可以省略

execution(* com.yzy.dao.BookDao.add(参数))

举例2:对com.yzy.dao.BookDao类里面的所有方法进行增强

execution(* com.yzy.dao.BookDao.*(参数))

举例3:对com.yzy.dao包里面的所有类,类里面所有方法进行增强

execution(* com.yzy.dao.*.*(参数))

  • AOP操作(AspectJ注解方式)

    1.创建一个类,在类里面定义方法

    //被增强类
    public class User {
        public void add(){
            System.out.println("add.....");
        }
    }
    

    2.创建增强类(编写增强逻辑)

    (1)在增强类里面,创建方法,让不同方法代表不同通知类型

    //增强的类
    public class UserProxy {
    
        //前置通知
        public void before(){
            System.out.println("before......");
        }
    }
    

    3.进行通知的配置

    (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: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="com.yzy.spring5.aopanno"></context:component-scan>
    </beans>
    

    (2)使用注解创建User和UserProxy对象

    @Component
    public class UserProxy {
        
    @Component
    public class User {
    

    (3)在增强类上面添加注解@Asepect

    @Component
    @Aspect
    public class UserProxy {
    

    (4)在spring配置文件中开启生成代理对象

    <!--开启Aspect生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    

    4.配置不同类型的通知

    在增强类的里面,在作为通知方法的上面添加通知类型注解,使用切入点表达式

@Component
@Aspect
public class UserProxy {

    //前置通知
    @Before(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("before......");
    }

    @After(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void after(){
        System.out.println("after.....");
    }

    @AfterReturning(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning.....");
    }

    @AfterThrowing(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing......");
    }

    @Around(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前......");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("环绕之后......");
    }
}

5.相同的切入点抽取

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

    //前置通知
    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("before......");
    }

6.多个增强类对同一个方法进行增强,设置增强类的优先级

在增强类上面添加注解@Order(数字类型值),数字值越小,优先级越高,从0开始.

@Component
@Aspect
@Order(1)
public class UserProxy2 {

    //前置通知
    @Before(value = "execution(* com.yzy.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("UserProxy2 before......");
    }
}

@Component
@Aspect
@Order(3)
public class UserProxy {

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

    //前置通知
    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("UserProxy before......");
    }
    
//UserProxy2的before()方法先执行

7.完全使用注解开发

创建配置类,不需要创建xml配置文件
在这里插入图片描述

  • AOP操作(AspectJ配置文件)

    1.创建两个类,增强类和被增强类,创建方法

    public class Book {
        public void buy(){
            System.out.println("buy......");
        }
    }
    
    public class BookProxy {
        public void before(){
            System.out.println("before.....");
        }
    }
    

    2.在spring配置文件中创建两个类对象

    <!--创建对象-->
        <bean id="book" class="com.yzy.spring5.aopxml.Book"></bean>
        <bean id="bookProxy" class="com.yzy.spring5.aopxml.BookProxy"></bean>
    

    3.在spring配置文件中配置切入点

    <!--配置aop增强-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="p" expression="execution(* com.yzy.spring5.aopxml.Book.buy(..))"/>
            
            <!--配置切面-->
            <aop:aspect ref="bookProxy">
                <!--配置增强作用在具体的方法上-->
                <aop:before method="before" pointcut-ref="p"></aop:before>
            </aop:aspect>
        </aop:config>
    

xy">




3.在spring配置文件中配置切入点

```xml
<!--配置aop增强-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* com.yzy.spring5.aopxml.Book.buy(..))"/>
        
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--配置增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值