Spring5-AOP操作

1、AOP概述

  • Aspect Oriented Programming的缩写,解释为面向切面(方面)编程
  • 可以对业务逻辑的各个部分进行隔离,降低业务逻辑之间的耦合度
  • 通俗来讲就是在不修改源代码的情况下增加新的功能

2、底层原理

  • 接口类的情况,使用JDK动态代理,通过创建接口实现类的代理对象方式,增强接口实现类中的方法
  • 普通类的情况,使用CGLIB动态代理,通过创建普通类的子类代理对象,实现对方法的增强

3、JDK动态代理实现

  • 使用java.lang.reflect.Proxy类中的newProxyInstance方法获取指定接口的实现类代理对象
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
  • 参数说明
    loader:代理类的类加载器
    interfaces:代理类要实现的接口列表,数组中的元素是Class类型
    h:InvocationHandler是一个接口,需要实现并且将实现类对象传递进去,实现类中加入增强主程序功能的代码
  • 代码演示
interface UserDao {
    public int add(int a, int b);

    public int update(int id);
}
public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
        System.out.println("开始执行add方法");
        return a + b;
    }

    @Override
    public int update(int id) {
        System.out.println("返回更新成功条数");
        return 1;
    }
}
public class Test01 {
    public static void main(String[] args) {
        //代理类要实现的接口
        Class[] interfaces = {UserDao.class};
        //参数:代理类的类加载器,代理类实现的接口列表,代理类对象实例实现接口并调用处理程序
        UserDao userDao = (UserDao)Proxy.newProxyInstance(UserDaoProxy.class.getClassLoader(), interfaces,
                new UserDaoProxy(new UserDaoImpl()));
        int result = userDao.add(100, 200);
        System.out.println("add方法的结果 " + result);
    }
}

class UserDaoProxy implements InvocationHandler {
    private UserDao userDaoObj;

    public UserDaoProxy(UserDao o) {
        this.userDaoObj = o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy:代理类对象实例,method:代理对象调用的方法对象,args:调用方法传递的参数
        System.out.println(method.getName() + "方法执行前");
        //通过反射机制,类方法对象指定对象实例调用方法
        Object result = method.invoke(userDaoObj, args);
        System.out.println(method.getName() + "方法执行后");
        return result;
    }
}

4、AOP术语

  • 连接点

类中可以被增强的方法,统称为连接点

  • 切入点

类中实际被增强的方法,称为切入点

  • 通知

代码中增加(增强)的逻辑代码部分,称为通知,包括前置通知、后置通知、环绕通知、异常通知、最终通知等

  • 切面

切面是一个动作,把通知应用到切入点的过程就叫切面

5、准备工作

  • Spring框架一般都是基于AspectJ实现AOP操作
    AspectJ是一个独立的框架,不属于Spring的组成部分,为了方便操作AOP,一般将Spring和AspectJ同时使用
  • 切入点表达式
    1、明确将要对某个类中的某个方法进行增强
    2、语法结构
    execution([权限修饰符][返回类型][类全路径][方法名称] ([参数列表]))
    3、使用举例:
    1)对UserDao类里面的add方法增强
    execution(* com.springstudy.aop.UserDao.add(..))
    符号 * 表示所有权限修饰符,返回类型可以省略
    2)对UserDao类里面所有方法增强
    execution(* com.springstudy.aop.UserDao.*(..))

6、AspectJ注解操作

  • 操作步骤
    1、创建增强类,使用@Component和@Aspect注解声明代理对象
    2、类中创建通知,使用@Before、@After、@AfterReturning、@AfterThrowing、@Around注解声明通知类型
    3、配置xml文件(也可以使用全注解开发),开启为@Aspect注解自动创建代理对象

  • 代码演示

@Component //声明对象
@Aspect //声明代理类
public class GoodsProxy {

    //前置通知,使用切入点表达式确定要增强的切入点
    @Before(value = "execution(* com.spring.aop.Goods.add(..))")
    public void before() {
        System.out.println("before...");
    }

    //最终通知
    @After(value = "execution(* com.spring.aop.Goods.add(..))")
    public void after() {
        System.out.println("after...");
    }

    //后置通知(返回通知)
    @AfterReturning(value = "execution(* com.spring.aop.Goods.add(..))")
    public void afterReturn() {
        System.out.println("after returning...");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.spring.aop.Goods.add(..))")
    public void afterThrowing() {
        System.out.println("after throwing...");
    }

    //环绕通知
    @Around(value = "execution(* com.spring.aop.Goods.add(..))")
    public void around(ProceedingJoinPoint p) throws Throwable {
        System.out.println("around before...");
        //执行切入点
        p.proceed();
        System.out.println("around after...");
    }
}



    
    

    
    


//执行结果
around before...
before...
goods add方法
after returning...
after...
around after...
//带有异常通知的执行结果
around before...
before...
goods add方法
after throwing...
after...

当切入点内有异常,执行异常通知后将直接执行最终通知,其他通知均不会执行

  • 通知顺序
    1、环绕前置通知(Around)
    2、前置通知(Before)
    3、切入点
    4、后置通知(AfterReturning)
    5、最终通知(After)
    6、环绕后置通知(Around)
  • 提取切入点表达式
//提取切入点表达式
@Pointcut(value = "execution(* com.spring.aop_annotation.Goods.add(..))")
public void cutPoint() {}

//前置通知
@Before(value = "cutPoint()")
public void before() {
    System.out.println("before...");
}
  • 当切入点有多个增强类,使用@Order注解排序
@Component
@Aspect
@Order(1) //数字越小,先执行
public class GoodsProxy 

7、AspectJ配置文件操作



    
    

    
    
        
        

        
        
            
            
        
    

8、完全注解

@Configuration //声明配置
@ComponentScan(basePackages = {"com.spring.aoptest"}) //注解扫描
@EnableAspectJAutoProxy(proxyTargetClass = true) //自动创建AspectJ代理对象
public class ConfigAop {
}

你可能感兴趣的:(Spring5-AOP操作)