• SpringAOP


    AOP实现原理

    Spring AOP 基于动态代理实现原理:
      ○ 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
      ○ 如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);

    AOP有关知识点(通知+aspect+pointcut)

    AOP通知类型:
    AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分
      前置通知(Before)
      后置通知(After)
      返回通知(After-returning)
      异常通知(After-throwing)
      环绕通知(Around)

    AOP重要的知识点。

    AOP切面:切点+通知

    SpringAOP+AspectJ实现步骤:
    1.坐标
    2.配置

     
           
                org.springframework
                spring-context
                5.3.28
           


           
                org.aspectj
                aspectjweaver
                1.9.7
           


       

    AspectJ 切面:可以理解为要注入方法的所有通知

    切点:到哪一个类的哪一个方法

    AOP实现流程

    1,正常的制作程序

     以上一篇的转账来说,事务管理注入到service的每一个方法当中。
    2,将非共性功能开发到对应的目标对象类中,并制作成切入点方法,绿色的都可以当切入点

      @Override
        public void save(String name) {

            System.out.println("===>业务新增");
            int a = 10/0;//模拟异常
        }

        @Override
        public int delete(int num) {
            System.out.println("===>业务删除");
            return 0;
        }

        @Override
        public void findAll() {
            System.out.println("===>业务查询");
        }

    3,将共性功能独立开发出来,制作成“通知”

    事务的开启到AOP前置通知的地方

    事务的提交可以放到AOP的返回通知的地方。

    事务失败可以放到AOP的异常通知的地方。

    事务关闭可以放到AOP的后置通知的地方。finally必须要执行的那个模块。

    1. package com.apesource.util;
    2. import org.aspectj.lang.JoinPoint;
    3. import org.aspectj.lang.ProceedingJoinPoint;
    4. import java.util.Date;
    5. /**
    6. * @author
    7. * @version 1.0
    8. * @since 2023/8/4
    9. */
    10. public class LoggerUtil {
    11. //前置通知
    12. public void beforeMethod(){
    13. System.out.println("前置通知=====>"+new Date());
    14. }
    15. //返回通知
    16. public void afterRrturnMethod(){
    17. System.out.println("返回通知=====>"+new Date());
    18. }
    19. //异常通知
    20. public void throwMethod(){
    21. System.out.println("异常通知=====>"+new Date());
    22. }
    23. //后置通知
    24. public void afterMethod(){
    25. System.out.println("后置通知=====>"+new Date());
    26. }
    27. //环绕通知
    28. public Object arroundMethod(ProceedingJoinPoint pjp){
    29. Object obj = null;
    30. try {
    31. //环绕通知---前置通知
    32. System.out.println("环绕通知---前置通知");
    33. Object[] objs = pjp.getArgs();
    34. obj = pjp.proceed(objs);
    35. //环绕通知---返回通知
    36. System.out.println("环绕通知---返回通知");
    37. } catch (Throwable throwable) {
    38. //环绕通知---异常通知
    39. System.out.println("环绕通知---异常通知");
    40. throwable.printStackTrace();
    41. } finally {
    42. //环绕通知---后置通知
    43. System.out.println("环绕通知---后置通知");
    44. }
    45. return obj;
    46. }
    47. }

    4.在配置文件中,声明“切入点”,该步骤可以让Spring定位到实体类的方法

    切点表达式配置语法:
    execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
    eg:
        execution(public void com.apesource.service.ServiceImp.findAll())
    1.修饰符可以省略代表任意
        execution(返回值 包名称.类名称.方法名称(参数列表))
    2.返回值可以使用“*”代表任意
        execution(* 包名称.类名称.方法名称(参数列表))
    3.包名可以使用“*”代表任意名称
        execution(* *.*.*.类名称.方法名称(参数列表))
    4.包名可以使用“..”代表任意个数
        execution(* *...类名称.方法名称(参数列表))
    5.类名与方法名可以使用“*”代表任意
        execution(* *...*.*(参数列表))
    6.参数列表可以使用".."代表任意个数任意类型
        execution(* *...*.*(..))
        如果有参数
            int======>int
            String===>java.lang.String

    @Pointcut(value = "execution(* com.apesource.service.*.*(..))")
        public  void dian(){
        }

    修饰符为任意,返回值任意, com.apesource.service下的所有类的所有方法。

    5.在配置文件中,声明"切入点"与"通知"间的关系(含通知类型),即"切面"

    @Component
    @Aspect
    public class LoggerUtil {


        @Pointcut(value = "execution(* com.apesource.service.*.*(..))")
        public  void dian(){
        }
        //前置通知
        @Before("dian()")
        public void beforeMethod(){
            System.out.println("前置通知=====>"+new Date());
        }
        //返回通知
        @AfterReturning("dian()")
        public void afterRrturnMethod(){
            System.out.println("返回通知=====>"+new Date());
        }
        //异常通知
        @AfterThrowing("dian()")
        public void throwMethod(){
            System.out.println("异常通知=====>"+new Date());
        }
        //后置通知
        @After("dian()")
        public void afterMethod(){
            System.out.println("后置通知=====>"+new Date());
        }

        //环绕通知
        @Around("dian()")
        public Object arroundMethod(ProceedingJoinPoint pjp){

            Object obj = null;

            try {
                //环绕通知---前置通知
                System.out.println("环绕通知---前置通知");
                Object[] objs = pjp.getArgs();
                obj = pjp.proceed(objs);//proceed等于invoke方法
                //环绕通知---返回通知
                System.out.println("环绕通知---返回通知");
            } catch (Throwable throwable) {
                //环绕通知---异常通知
                System.out.println("环绕通知---异常通知");
                throwable.printStackTrace();
            } finally {
                //环绕通知---后置通知
                System.out.println("环绕通知---后置通知");
            }

            return obj;

        }

    ●运行阶段(AOP完成)=============spring帮我们做的
        ◆Spring容器加载配置文件,监控所有配置的“切入点”方法的执行
        ◆当监控到“切入点”方法被运行,使用“代理”机制,动态创建“目标对象”的“代理对象”,
     根据“通知类别”,在“代理对象”的对应位置将“通知”对应的功能“织入”,完成完整的代码逻辑并运行 

       
       

    1. <!--开启aop配置xml版本-->
    2. <!-- <aop:config>-->
    3. <!-- <aop:aspect id="mian" ref="loggerUtil">-->
    4. <!-- <aop:pointcut id="dian" expression="execution(* com.apesource.service.*.*(..))"/>-->
    5. <!-- <aop:before method="beforeMethod" pointcut-ref="dian"></aop:before>
    6. <!-- <aop:after-returning method="afterRrturnMethod" pointcut-ref="dian"></aop:after-returning>
    7. <!-- <aop:after-throwing method="throwMethod" pointcut-ref="dian"></aop:after-throwing>-->
    8. <!-- <aop:after method="afterMethod" pointcut-ref="dian"></aop:after>&ndash;&gt;-->
    9. <!-- <aop:around method="arroundMethod" pointcut-ref="dian"></aop:around>-->
    10. <!-- </aop:aspect>-->
    11. <!-- </aop:config>-->
    12. <!--开启aop配置注解版-->
    13. <context:component-scan base-package="com.apesource"></context:component-scan>
    14. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

     test测试类。

    1. package com.apesource.test;
    2. import com.apesource.service.IService;
    3. import org.springframework.context.ApplicationContext;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. /**
    6. * @author
    7. * @version 1.0
    8. * @since 2023/8/4
    9. */
    10. public class Test01 {
    11. public static void main(String[] args) {
    12. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    13. IService service = (IService) applicationContext.getBean("serviceImp");
    14. service.save("今天周五");
    15. // service.delete(5);
    16. // service.findAll();
    17. }
    18. }

  • 相关阅读:
    Linux基础篇之文件权限问题讲解
    Git的基础操作及使用
    JavaSE入门---认识Java数组
    C++ 两类头文件相互包含的解决方法
    02、RocketMQ -- 应用场景、核心概念
    5分钟了解Gradle并构建java项目
    双臂二指魔方机器人的制作(三)--还原控制
    内网穿透的应用-如何搭建WordPress博客网站,并且发布至公网上?
    C语言进阶之冒泡排序
    .Net Core Entity Framework Core 的单数据源基础封装(mysql)
  • 原文地址:https://blog.csdn.net/weixin_51704612/article/details/132955892