SpringAOP实现

1、导入依赖

XML 复制代码
        <!--SpringAOP的织入包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.19</version>
        </dependency>

2、创建AppConfig配置类

复制代码
@Configuration:配置类注解,使用该注解的类为一个配置类,其中用于定义交给Spring管理的各个方法@ComponentScan("com.jiazhong.dao.impl"):组件扫描器注解
    - 该注解会自动扫描指定包中的所有类,并将扫描到的类中带有@Component注解的类管理起来
java 复制代码
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration //配置注解
@ComponentScan({"com.jiazhong.service","com.jiazhong.aspects"}) //组件扫描器注解
//@ComponentScan("com.jiazhong") 扫描com.jiazhong包下的所有类
public class AppConfig {
}

3、创建UserService接口及其实现类UserServiceImpl

java 复制代码
public interface UserService {
    void add();
    void queryAll();
    String queryByName(String name);
    void del(int id);
}
复制代码
@Service("userService"):Spring的服务层对象注解,它和@Component注解功能一样,只是语义更加明确
    - 在Service层使用该注解
java 复制代码
import com.jiazhong.service.UserService;
import org.springframework.stereotype.Service;

@Service("userService") //Spring的服务层对象注解,@Component注解功能一样
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("执行UserServiceImpl---->add方法......");
    }

    @Override
    public void queryAll() {
        System.out.println("执行UserServiceImpl---->queryAll方法......");
    }

    @Override
    public String queryByName(String name) {
        System.out.println("执行UserServiceImpl---->queryByName方法......");
        //throw new RuntimeException();
        return "java"+name;
    }

    @Override
    public void del(int id) {
        System.out.println("执行UserServiceImpl---->del方法......");
    }
}

4、创建切面类MyAspect

复制代码
 切入点定义,需要定义两个元素:
 1.切入点声明(private void myPointCut(){})
  - 在SpringAOP中切入点的声明其实就是方法定义,但无参数和方法体
  - 切入点的名称为方法名,在引用切入点时需要使用"方法名()"
 2.定义切入点表达式,由 @Pointcut注解定义
 @Pointcut:切入点表达式注解,通过切入点表达式对要拦截的方法描述
 execution:在其中编写切入点表达式
  - 切入点表达式是用于描述方法
java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
@Aspect //切面注解
@Component //当前类扔给Spring管理
@EnableAspectJAutoProxy //启用springAOP的自动代理功能
//切入点声明
public class MyAspect {
    //切入点表达式注解
    @Pointcut("execution(void com.jiazhong.service.impl.UserServiceImpl.add())")
    //切入点声明    
    private void myPointCut(){}
}

对于切入点表达式还有以下写法,并分别注释了其意思

java 复制代码
    //切入点定义拦截add方法
    @Pointcut("execution(void com.jiazhong.service.impl.UserServiceImpl.add())")

    //切入点定义拦截queryByName方法
    @Pointcut("execution(String com.jiazhong.service.impl.UserServiceImpl.queryByName(String))")

    //切入点定义拦截UserServiceImpl类中的所有方法,第一个*是所有类型,第二个*是类中所有方法,(..)是方法中的任意类型的任意参数
    @Pointcut("execution(* com.jiazhong.service.impl.UserServiceImpl.*(..))")

    //切入点定义拦截com.jiazhong.service包及其子包中的任意类任意方法
    @Pointcut("execution(* com.jiazhong.service..*.*(..))")

    //切入点定义不拦截指定的方法queryAll
    @Pointcut("!execution(void com.jiazhong.service.impl.UserServiceImpl.queryAll())")
复制代码
切面类,切面中包含两个元素:
  1.切入点,用于定义连接点的
  2.通知,拦截到连接点后要做的具体事情
   - 前置通知,在目标方法执行前执行
   - 后置通知,在目标方法执行后执行
   - 异常通知,在目标方法出现异常后执行
   - 最终通告,无论目标方法是否出现异常都会执行

①前置通知

java 复制代码
    /**
     * @Before("myPointCut()"):前置通知注解,myPointCut()指定切入点
     */
    @Before("myPointCut()")
    public void beforeAdvice(){
        System.out.println("前置通知被执行......");
    }

② 后置通知

java 复制代码
    /**
     * 后置通知,当目标方法调用后执行,但如果目标方法出现异常则不执行
     */
    @AfterReturning("myPointCut()")
    public void afterReturningAdvice(){
        System.out.println("后置通知被执行......");
    }

③异常通知

java 复制代码
    /**
     * 异常通知,在目标方法出现异常时执行
     */
    @AfterThrowing("myPointCut()")
    public void throwAdvice(){
        System.out.println("异常通知被执行......");
    }

④最终通知

java 复制代码
    /**
     * 最终通知,无论是否出现异常都被执行
     */
    @After("myPointCut()")
    public void afterAdvice(){
        System.out.println("最终通知被执行......");
    }

⑤环绕通知

复制代码
 环绕通知可以替换前面的所有通知
 原则:在环绕通知内部必须手动调用目标方法
 环绕通知带有参数ProceedingJoinPoint(处理连接点),使用该参数可以发起对目标方法的调用
java 复制代码
    /**
     * 环绕通知,可以在目标方法调用前、调用后、出现异常后自定义要执行的内容
     */
    @Around("myPointCut()")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("环绕通知:前置通知。。。。。");
            //调用目标方法
            //目标方法的返回值就是proceed方法的返回值
            String msg = (String) proceedingJoinPoint.proceed();
            System.out.println(msg);
            System.out.println("环绕通知:后置通知。。。。。");
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("环绕通知:异常通知。。。。。");
        }finally {
            System.out.println("环绕通知:最终通知。。。。。");
        }
    }

此处的实例是:

java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
@Aspect
@Component
@EnableAspectJAutoProxy
public class MyAspect {
    @Pointcut("execution(void com.jiazhong.service.impl.UserServiceImpl.add())")
    private void myPointCut(){}
    @Before("myPointCut()")
    public void beforeAdvice(){
        System.out.println("前置通知被执行......");
    }

5、UserTest测试类

java 复制代码
public class UserTest {
    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = (UserService) context.getBean("userService");

        userService.add();
    }
}
复制代码
----SpringAOP注解
@Aspect:切面注解,在类上使用,表示该类为一个切面类
@EnableAspectJAutoProxy:启用SpringAOP的自动代理注解
@Pointcut:定义切入点表达式注解
@Before("切入点"):前置通知注解
@AfterReturning("切入点"):后置通知注解
@AfterThrowing("切入点"):异常通知注解
@After("切入点"):最终通知注解
@Around("切入点"):环绕通知注解
相关推荐
二哈赛车手8 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
代码搬运媛8 小时前
Jest 测试框架详解与实现指南
前端
栗子~~9 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
YDS8299 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
counterxing9 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq9 小时前
windows下nginx的安装
linux·服务器·前端
之歆10 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜10 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai1080810 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
未若君雅裁10 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis