Spring AOP复习与回顾

AOP
  1. 什么是AOP

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

    • 通俗描述:不通过修改源代码的方式,在主肝功能里面添加新功能

  2. AOP底层原理

    AOP底层使用动态代理:

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

    ②没有接口的情况,使用CGLIB动态代理 创建子类的代理对象,增强类的方法

    JDK动态代理演示

    创建UserDao接口以及其对应的实现类UserDaoImpl:

    package com.dxy.spring5.dao;
    
    /**
     * Description: <br/>
     * date: 2022/11/16 17:30
     *
     * @author dxy
     * @since JDK 1.8
     */
    public interface UserDao {
        public void print();
        public int add(int a,int b);
    }
    
    package com.dxy.spring5.dao;
    
    import org.springframework.stereotype.Repository;
    
    /**
     * Description: <br/>
     * date: 2022/11/16 17:31
     *
     * @author dxy
     * @since JDK 1.8
     */
    @Repository
    public class UserDaoImpl implements UserDao{
    
        public void print() {
            System.out.println("dao test...");
        }
    
        public int add(int a,int b) {
            System.out.println("add方法执行...");
            return a+b;
        }
    }
    

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

    package com.dxy.spring5;
    
    import com.dxy.spring5.dao.UserDao;
    import com.dxy.spring5.dao.UserDaoImpl;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    
    /**
     * Description: <br/>
     * date: 2022/11/16 17:33
     *
     * @author dxy
     * @since JDK 1.8
     */
    public class JDKProxy {
        public static void main(String[] args) {
            //创建接口代理类实现对象
            Class[] interfaces={UserDao.class};
            UserDao instance = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
                UserDaoImpl userDao = new UserDaoImpl();
                //增强的逻辑
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //方法前
                    System.out.println("方法前..." + method.getName() +"传递的参数为:"+ Arrays.toString(args));
                    //被增强的方法执行
                    Object invoke = method.invoke(userDao, args);
                    //方法后
                    System.out.println("方法后..." + method.getName() +"传递的参数为:"+ Arrays.toString(args));
    
                    return invoke;
                }
            });
            int res = instance.add(10, 20);
            System.out.println(res);
    
        }
    }
    

    输出结果:

    方法前...add传递的参数为:[10, 20]
    add方法执行...
    方法后...add传递的参数为:[10, 20]
    30
    
  3. AOP中的主要术语

    • 连接点:类中可以被增强的方法称为连接点

    • 切入点:真正被增强的方法,称为切入点

    • 通知(增强):实际增强的逻辑部分称为通知

      有前置通知,后置通知,环绕通知,异常通知,最终通知五种类型

    • 切面: 把通知应用到切入点的过程

  4. Spring中一般都是基于AspectJ实现AOP操作

    ①创建要被增强的类及方法

    ②创建增强类

    ③通知的配置:

    • 在Spring配置文件中,开启注解扫描
    • 使用注解创建User和UserProxy对象
    • 在增强类上面添加注解@Aspect
    • 在Spring配置文件中开启生成代理对象

    ④配置不同类型的通知

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

    基于AspectJ使用注解实现AOP操作的演示

    创建User类,作为要被增强的类,里面有连接点

    package com.dxy.spring5.aopanno;
    
    import org.springframework.stereotype.Component;
    
    /**
     * Description: <br/>
     * date: 2022/11/16 18:56
     *
     * @author dxy
     * @since JDK 1.8
     */
    //被增强的类
    @Component
    public class User {
        public void add(){
            
            System.out.println("add...");
        }
    }
    

    创建UserProxy类,作为增强类,里面写我们的增强逻辑

    package com.dxy.spring5.aopanno;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    /**
     * Description: <br/>
     * date: 2022/11/16 18:57
     *
     * @author dxy
     * @since JDK 1.8
     */
    //增强类
    @Component
    @Aspect  //生成代理对象
    public class UserProxy {
        
        //相同切入点抽取
        @Pointcut(value = "execution(* com.dxy.spring5.aopanno.User.add(..))")
        public void pointdemo(){
    
        }
        
        
        //@Before表示前置通知,即在要增强的方法之前执行
        /*  execution(* com.dxy.spring5.aopanno.User.add(..))为切入点表达式
            参数为[权限修饰符][返回值类型][包名+类名+方法名][参数列表]
            权限修饰符位置一般用*,表示所有权限都可以 返回值类型可以不写 参数列表用..表示
         */
        @Before(value = "execution(* com.dxy.spring5.aopanno.User.add(..))")
        public void before(){
            System.out.println("before...");
        }
        //最终通知  相同切入点抽取
        @After(value = "pointdemo()")
        public void after(){
            System.out.println("after...");
        }
        //后置通知(返回通知)
        @AfterReturning(value = "execution(* com.dxy.spring5.aopanno.User.add(..))")
        public void afterReturning(){
            System.out.println("afterReturning...");
        }
        //异常通知
        @AfterThrowing(value = "execution(* com.dxy.spring5.aopanno.User.add(..))")
        public void afterThrowing(){
            System.out.println("afterThrowing...");
        }
        //环绕通知
        @Around(value = "execution(* com.dxy.spring5.aopanno.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前....");
            //执行被增强的方法
            proceedingJoinPoint.proceed();
            System.out.println("环绕之后....");
    }
    
    
    }
    

    创建bean1.xml进行配置

    <?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="com.dxy.spring5"></context:component-scan>
    
            <!--开启AspectJ生成代理对象-->
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
    

    或 使用配置类进行配置

    @Configuration    //作为配置类,替代xml配置文件
    @ComponentScan(basePackages = {"com.dxy"})
    @EnableAspectJAutoProxy
    public class SpringConfig {
    
    }
    

    进行测试

    @Test
        public void testAopAnno(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
            User user = context.getBean("user", User.class);
            user.add();
        }
    

    输出

    环绕之前....
    before...
    add...
    afterReturning...
    after...
    环绕之后....
    

    当切入点有异常时(这里我们自己创造一个异常)

    @Component
    public class User {
        public void add(){
            int a=10/0;
            System.out.println("add...");
        }
    }
    

    输出为

    环绕之前....
    before...
    afterThrowing...
    after...
    
        
    +异常信息
    

    ps. 如果有多个增强类对同一个方法进行增强,则可在增强类上添加注解@Order(数字类型值),值越小优先级越高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值