AOP的概念及其使用

一、AOP的概念 

1、Aspect Oriented Programming 面向切面编程

使用范围:

        交叉业务:非核心功能,又散落在到处;而且还是不得不处理的功能

2、特点

(1)、程序员只需要关注核心业务,交叉业务将交给切面

(2)、由于使用动态代理模式,核心类和切面之间是没有直接的耦合关系

3、常用概念

切面:又被称为方面,指的是交叉业务,通常:1个交叉业务,对应1个切面

切入点:满足切面切入条件的点,就是切入点

连接点:当切面正式进入到某一个切入时,该切入点就是连接点

通知:又被称为增强,实际上就是切面的代码(前置通知,后置通知,后置返回通知,后置异常通知,环绕通知)

目标对象:需要被切面进行增强的对象

代理对象:使用JDK代理或CGLIB代理,针对目标对象创建出来的代理实例!

织入:AOP切面应用到切入点的过程,就是织入

二、使用方式

step1:导入相关的jar包

<!-- 导入第3方的切面相关Jar包-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.8</version>
    <scope>runtime</scope>
</dependency>

step2:创建切面对象

import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

/**
 * 事务切面
 * @Aspect 将该Java类声明为一个切面
 *
 */
@Aspect
@Component
public class TransactionAspect {


}

step3: 定义条件表达式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
                throws-pattern?)

   /**
     * 定义条件表达式
     */
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.save(..))")
    private void pointcut01(){}
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.update(..))")
    private void pointcut02(){}
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.delete(..))")
    private void pointcut03(){}

step4:添加通知

(1)前置通知

/**
     * 前置通知
     * 作用:获得SqlSession
     * @param joinPoint 连接点
     */
@Before("pointcut01() || pointcut02() || pointcut03()")
public void beforeAdvice(JoinPoint joinPoint){
    System.out.println("前置通知,我运行在目标方法执行之前!");

    Object obj = joinPoint.getTarget();//得到目标对象
    System.out.println(obj);
    String name = joinPoint.getSignature().getName();//得到目标方法
    System.out.println(name);
    Object[] args = joinPoint.getArgs();
    System.out.println(Arrays.toString(args));//得到目标参数
}

(2)后置返回通知:执行在目标方法成功执行之后

/**
     * 后置返回通知
     * @param joinPoint
     * @param res
     */
@AfterReturning(value = "pointcut01() || pointcut02() || pointcut03()",returning = "res")
public void afterReturnAdvice(JoinPoint joinPoint,Object res){
    System.out.println("我是后置返回通知,我执行在目标方法正常执行之后!");
    System.out.println(res);
}

(3)后置异常通知 执行在目标方法抛出异常之后 

/**
     * 后置异常通知
     * @param joinPoint
     * @param res 异常
     */
@AfterThrowing(value="pointcut01() || pointcut02() || pointcut03()",throwing = "res")
public void afterThrowsAdvice(JoinPoint joinPoint,Exception res){
    System.out.println("我是后置异常通知,我执行在目标方法抛出异常之后!");
    System.out.println(res);
}

(4) 后置通知

/**
     * 后置通知
     * @param joinPoint
     */
@After("pointcut01() || pointcut02() || pointcut03()")
public void afterAdvice(JoinPoint joinPoint){
    System.out.println("我是后置通知,不管目标方法能否正常执行,我都执行!");
}

 (5)环绕通知 风险高,这玩意相当于:@Before + @After 能用@Before + @After搞定的事情,一定不要用@Around

/**
     * 环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
@Around("pointcut01() || pointcut02() || pointcut03()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("我是环绕通知,我最NB!属于无法无天的……");
    Object[] args = pjp.getArgs();//原始的参数
    args[0] = null;
    Object result = pjp.proceed(args);//调用目标方法(如果不写,目标方法将不执行)

    return result;
}

 完整代码

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.Arrays;

/**
 * 事务切面
 * @Aspect 将该Java类声明为一个切面
 *
 */
@Aspect
@Component
public class TransactionAspect {

    /**
     * 定义条件表达式
     * execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.*(..))   最常见的表达式
     */
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.save(..))")
    private void pointcut01(){}
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.update(..))")
    private void pointcut02(){}
    @Pointcut("execution(* com.woniuxy.stall.*mag.service.impl.*ServiceImpl.delete(..))")
    private void pointcut03(){}

    /**
     * 前置通知
     * 作用:获得SqlSession
     * @param joinPoint 连接点
     */
    @Before("pointcut01() || pointcut02() || pointcut03()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("前置通知,我运行在目标方法执行之前!");

        Object obj = joinPoint.getTarget();//得到目标对象
        System.out.println(obj);
        String name = joinPoint.getSignature().getName();//得到目标方法
        System.out.println(name);
        Object[] args = joinPoint.getArgs();
        System.out.println(Arrays.toString(args));//得到目标参数
    }

    /**
     * 后置返回通知
     * @param joinPoint
     * @param res
     */
    @AfterReturning(value = "pointcut01() || pointcut02() || pointcut03()",returning = "res")
    public void afterReturnAdvice(JoinPoint joinPoint,Object res){
        System.out.println("我是后置返回通知,我执行在目标方法正常执行之后!");
        System.out.println(res);
    }

    /**
     * 后置异常通知
     * @param joinPoint
     * @param res 异常
     */
    @AfterThrowing(value="pointcut01() || pointcut02() || pointcut03()",throwing = "res")
    public void afterThrowsAdvice(JoinPoint joinPoint,Exception res){
        System.out.println("我是后置异常通知,我执行在目标方法抛出异常之后!");
        System.out.println(res);
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After("pointcut01() || pointcut02() || pointcut03()")
    public void afterAdvice(JoinPoint joinPoint){
        System.out.println("我是后置通知,不管目标方法能否正常执行,我都执行!");
    }

    /**
     * 环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pointcut01() || pointcut02() || pointcut03()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("我是环绕通知,我最NB!属于无法无天的……");
        Object[] args = pjp.getArgs();//原始的参数
        args[0] = null;
        Object result = pjp.proceed(args);//调用目标方法(如果不写,目标方法将不执行)

        return result;
    }
}
六、注解作为切入点
import java.lang.annotation.*;

/**
 * 自定义一个日志注解
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {

    /**
     * 菜单的名称
     * @return
     */
    String menuName() default "";

    /**
     * 操作类型:CUD
     * @return
     */
    String optType() default "";

}

step5:开启代理支持

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启容器的自动扫描-->
    <context:component-scan base-package="com.woniuxy.stall"></context:component-scan>

    <!--开启AOP的动态代理功能-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

三、注解作为切入点

import java.lang.annotation.*;

/**
 * 自定义一个日志注解
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {

    /**
     * 菜单的名称
     * @return
     */
    String menuName() default "";

    /**
     * 操作类型:CUD
     * @return
     */
    String optType() default "";

}

操作日志通知

import com.woniuxy.stall.anno.MyLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 操作日志
 */
@Aspect
@Component
public class OptLogAspect {

    @AfterReturning(value = "@annotation(log)",returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result,MyLog log){
        System.out.println("模块的名称:" + log.menuName());
        System.out.println("操作的类型:"+log.optType());
        System.out.println("操作的数据:" + Arrays.toString(joinPoint.getArgs()));
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Spring框架中,IOC(控制反转)和AOP(面向方面编程)是两个核心概念。IOC是指通过Spring容器来管理对象的创建和依赖关系的过程,将对象的创建和依赖关系的维护交给了Spring容器来完成,从而实现了对象之间的解耦合。\[1\]而AOP是指通过在程序运行期间动态地将一些通用的横切关注点(如日志记录、事务管理等)与业务逻辑代码分离开来,从而提高代码的可维护性和可重用性。\[1\]在Spring中,可以通过配置文件或注解的方式来实现IOC和AOP的功能。例如,可以使用XML配置文件来定义Bean,并通过Spring容器来管理这些Bean的创建和依赖关系。\[2\]同时,Spring还提供了与ORM框架的整合,例如与Hibernate框架的整合,通过Spring的支持类简化了Hibernate的操作。\[3\]总的来说,Spring框架通过IOC和AOP概念,实现了对象之间的解耦合和通用关注点的分离,提供了一种轻量级的容器框架。 #### 引用[.reference_title] - *1* *3* [Spring中的IOC和AOP是什么意思?](https://blog.csdn.net/weixin_45704311/article/details/124295453)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [spring框架两大核心:IOC和AOP的详解](https://blog.csdn.net/qq_49755675/article/details/125642564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值