AOP基本知识

知识点1:概念

  • AOP:面向切面编程,利用AOP可以对业务逻辑的各个部分隔离开,降低代码的耦合度,提高可复用性。
  • 个人理解:不修改源代码,而是在主干功能里添加新的功能,很想设计模式中的装饰者设计。

知识点2:底层原理

  1. 使用到了动态代理
  • 情况一:有接口,使用JDK动态代理;-->创建接口实现类代理对象,增强类的方法
  • 情况二:无接口,使用CGLIB动态代理。-->创建子类的代理对象,增强类的方法

知识点3: JDK动态代理实现

代码:

package com.guodaxia.AOP.dao;
//接口
public interface UserDao {
    int add(int a,int b);
    int id(int id);
}

//实现类
public class UserDaoImpl implements UserDao{

    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public int id(int id) {
        id +=1;
        return id;
    }
}

代理类

package com.guodaxia.AOP.dao;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Objects;

public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类代理对象

        //实现类的接口
        Class[] interfaces = {UserDao.class};
        //第三个参数:代理类的接口InvocationHandler对象,由于接口不能直接创建对象,这里使用匿名内部类
        UserDao dao= (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
            //将旧的业务逻辑对象传递
            //匿名内部类不允许有构造方法,写一个静态代码块,
            // 在静态代码块new想要代理的对象,把他赋值给代码块外部的变量
            UserDao userDao;
            {
                Objects obj;
                userDao = new UserDaoImpl();
            }

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

                //增强业务逻辑中
                Object res = method.invoke(userDao, args);

                System.out.println("方法之后执行..." + method.getName() +":"+ res);
                return res;
            }
        });

        int result = dao.add(1,1);
        System.out.println(result);
        System.out.println("-----------------");
        int id = dao.id(006);
        System.out.println(id);
    }
}

总结

  1. 动态代理的好处在于可以在源代码的基础上,实现添加新功能;
  2. java包下有Proxy类用于用于创建代理;
  3. newProxyInstance(classLoad,interfaces,增强业务类)。

知识点3:术语

  1. 连接点:能够被增强的方法;
  2. 切入点:实际被增强的方法;
  3. 通知(增强):实际增强的逻辑部分,如日志更新,事务;

通知类型:

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知
  1. 切面:把通知应用到切入点的过程。

知识点4:AOP操作

准备

  • 使用AspectJ框架+spring框架完成AOP操作
  • 导入依赖

aop的jar包:

[com.springsource.net.sf.cglib-2.2.0.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.net.sf.cglib-2.2.0.jar)

[com.springsource.org.aopalliance-1.0.0.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.org.aopalliance-1.0.0.jar)

[com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar](......\dataFile\spring5\资料\资料\2 其他jar包\aop的jar包\com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar)

spring的jar包:

spring-aspects-5.2.6.RELEASE.jar

  • 切入点的表达式:知道对哪个类里面的 哪个方法进行增强。
  • 切入点语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])

@Aspect注解**

步骤:

  1. 创建需要被增强的类和方法;
//被增强的类
@Component
public class User {
    //被增强的方法
    public void add(){
        System.out.println("add..........");
    }
}
  1. 创建增强类,并编写增强业务逻辑代码;
//增强的类
@Component
@Aspect
public class UserProxy {

    //不同的方法代表着不同通知类型

    //1. 前置通知
    @Before(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void before(){
        System.out.println("before.........");
    }
    //2. 后置通知

    //3. 环绕通知

    //4. 异常通知

    //5. 终止通知
}
  1. xml开启注解扫描 or 创建配置类开启注解扫描;
<?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.guodaxia.AOP.aopaspect"></context:component-scan>
</beans>
  1. 使用四大注解任何一个创建User和UserProxy对象;

  2. 在增强类上面添加注解@Aspect,自动生成代理对象;

  3. 在spring配置中开启生成代理对象;

  4. 配置不同类型的通知

  • 即在增强类中的方法上方添加通知类型注解,使用切入点表达式配置。
    //不同的方法代表着不同通知类型

    //1. 前置通知
    @Before(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void before(){
        System.out.println("before.........");
    }
	//2. 后置通知
    @After(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void after(){
        System.out.println("after .......");
    }
    //5. 最终通知
    @AfterReturning(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void afterReturning(){
        System.out.println("afterReturning .......");
    }
    //3. 环绕通知
    @Around(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Around before,,,,");
        pjp.proceed();//被增强的方法执行
        System.out.println("Around after......");
    }
    //4. 异常通知
    @AfterThrowing(value = "execution(* com.guodaxia.AOP.aopaspect.User.add())")
    public void afterThrowing(){
        System.out.println("AfterThrowing .......");
    }

执行结果

Around before,,,,
before.........
add..........
Around after......
after .......
afterReturning .......

总结:

  1. 一步一步慢慢来,分开配置,总能分解一个复杂的问题,总能汇成解决一个复杂的问题。
  2. 有些bug很小,跟着步骤一步一步检验,总能找到问题所在。
posted @ 2023-06-09 16:43  郭培鑫同学  阅读(14)  评论(0编辑  收藏  举报