aop详解

1、概述

提供声明式,允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。例add()加日志功能,这个地方就是横切关注点
  • 切面:横切关注点被模块化的对象,一个类。例:log类
  • 通知:切面要完成的工作。类中的方法。例:log中的方法
    • 五大通知执行顺序
      • Spring4.0
            正常情况:环绕前置=@Before目标方法执行=环绕返回=环绕最终=@After=@AfterReturning
            异常情况:环绕前置
        =@Before目标方法执行=环绕异常=环绕最终=@After=====@AfterThrowing
      • Spring5.28
            正常情况:环绕前置=@Before=目标方法执行=@AfterReturning=@After=环绕返回=环绕最终
            异常情况:环绕前置=@Before=目标方法执行=@AfterThrowing=@After=环绕异常=环绕最终
  • 目标: 被通知的对象
  • 代理:代理类
  • 切入点: 切面通知指定的地点
  • 连接点:与切入点匹配的执行点

2、使用

2.1、方式1:>Spring的API接口

1.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: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/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--注册bean-->
    <bean id="userService" class="com.moral.service.UserServiceImpl"/>
    <bean id="log" class="com.moral.log.Log"/>
    <bean id="afterLog" class="com.moral.log.AfterLog"/>

    <!--方式一:原生SpringAPI接口-->
    <!--配置aop-->
    <aop:config>
        <!--切入点 expression:表达式,execution(要执行的位置! * * * * *) .方法(参数)-->
        <aop:pointcut id="pointCut" expression="execution(* com.moral.service.UserServiceImpl.*(..))"/>
        <!--执行环绕增强-->
        <!--哪个类切入到哪里-->
        <aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
    </aop:config>
</beans>

2.AfterLog

public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法,返回结果:" + returnValue);
    }
}

3.Log

public class Log implements MethodBeforeAdvice {
    /*
    * method:要执行的目标对象的方法
    * args:参数
    * target:目标对象
    * */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");
    }
}

4.Test

@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //动态代理代理的是接口
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();
}
2.2、方式:2:自定义类实现AOP
1.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: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/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--方式2:自定义类,(切面)-->
    <bean id="diy" class="com.moral.diy.DiyPointCut"/>
    <aop:config>
        <aop:aspect ref="diy">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.moral.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

2.切面类

public class DiyPointCut {

    public void before(){
        System.out.println("===方法执行前===");
    }

    public void after(){
        System.out.println("===方法执行后===");
    }
}

3.Test

//方式2
@Test
public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //动态代理代理的是接口
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();
}
2.3、方式3:注解实现AOP

1.xml

<!--方式3:注解-->
<bean id="annotationPointCut" class="com.moral.diy.AnnotationPointCut"/>
<!--开启注解支持,默认jdk实现(false)->proxy-target-class="false";true:cglib-->
<aop:aspectj-autoproxy/>

2.切面类

@Aspect
public class AnnotationPointCut {
    //execution(修饰符  返回值  包名.类名/接口名.方法名(参数列表)),这里修饰符忽略
    @Before("execution(* com.moral.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }

    @After("execution(* com.moral.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }

    @Around("execution(* com.moral.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前");
        //方法执行
        Object o = joinPoint.proceed();
        System.out.println("环绕后");
    }
}

3.Test

//方式3:注解
 /*
    * 执行结果:
    1.环绕前
    2.方法执行前
    3.添加了一个用户
    4.方法执行后
    5.环绕后
    * */
@Test
public void test03(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //动态代理代理的是接口
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();
}
posted @   jpy  阅读(5)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示