当前位置: 首页 > news >正文

SpringAOP底层原理

目录

两种实现方式

JDK动态代理

编写接口

接口的实现类

创建代理对象

测试

CGLIB动态代理

需要增强的方法

创建代理对象

测试

 关于两种代理需要知道的点


两种实现方式

SpringAOP底层根据接口的使用情况,有两种的实现方式

  1. 有接口的时候:使用jdk动态代理
  2. 没有接口的情况:使用cglib动态代理

JDK动态代理

编写接口

package com.heaboy.aopdemo.jdkproxy;

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

接口的实现类

package com.heaboy.aopdemo.jdkproxy;


 public class Target implements TargetInteface {
    @Override
    public void method1() {
        System.out.println("method1 running ...");
    }

    @Override
    public void method2() {
        System.out.println("method2 running ...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

创建代理对象

对于代码的解析已写在注释中方便理解,这里在invoke调用前后都添加通知 => 环绕通知

package com.heaboy.aopdemo.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TargetProxy {
    public static <T> Object getTarget(T t) {
        //Proxy.newProxyInstance中的三个参数,分别对应下面的三个传入数据
        //ClassLoader loader:用来知名生成代理对象所使用的类加载器
        //Class<?> interfaces 用来知名目标类实现的所有接口
        //InvocationHandler h 里面的方法就是这个代理对象要做的事情
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
            //实现InvocationHandler接口后,需要重写invoke方法,invoke方法用于调用被代理对象的方法
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
                //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
                System.out.println("执行方法前...");
                Object invoke = method.invoke(t, args);
                System.out.println("执行方法后...");
                return invoke;
            }
        });
    }
}

测试

package com.heaboy.aopdemo.jdkproxy;

public class TargetUser {

    public static void main(String[] args) {
        TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
        target.method1();
        System.out.println("-----------------------------");
        target.method2();
        System.out.println("-----------------------------");
        System.out.println(target.method3(3));
    }

}

 

CGLIB动态代理

需要增强的方法

package com.heaboy.aopdemo.cglibproxy;


public class Target {
    public void method1() {
        System.out.println("method1 running ...");
}

    public void method2() {
        System.out.println("method2 running ...");
    }

    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

创建代理对象

package com.heaboy.aopdemo.cglibproxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class TargetProxy {

    public static <T> Object getProxy(T t) {
        Enhancer en = new Enhancer(); //使用Enchancer为无接口类创建代理对象
        en.setSuperclass(t.getClass());//设置要代理的目标类
        en.setCallback(new MethodInterceptor() {//代理类需要完成的工作
            //重写intercept方法
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("执行方法前。。。");
                //调用原有方法  
                Object invoke = methodProxy.invokeSuper(object, args);
                // Object invoke = method.invoke(t, args);// 作用等同与上面。
                System.out.println("执行方法后。。。");
                return invoke;
            }
        });
        //返回创建好的代理类对象
        return en.create();
    }
}

测试

package com.heaboy.aopdemo.cglibproxy;


import java.util.ArrayList;
import java.util.List;

public class TargetUser {

    public static void main(String[] args) {
        //创建代理类
        Target target = (Target) TargetProxy.getProxy(new Target());
        //打印生成的代理类全限定类名
        System.out.println(target.getClass().getName());
        //调用代理类方法
        target.method1();
    }

}


 关于两种代理需要知道的点

  • SpringAOP生成动态代理对象
    • 实现了接口:JDK动态代理
    • 无接口类:CGLIB动态代理
  • SpringAOP生成动态代理对象不需要特殊编译器
  • SpringAOP可以根据目标对象是否实现接口,自动选择代理模式
  • 优先对接口创建代理,方便程序的解耦与维护
  • 被final标记的方法 -> 方法不能重写 -> 无法被代理

相关文章:

  • 【高等数学基础进阶】多元函数的极值与最值
  • QT使用MSVC编译器时中文报错问题
  • Java Double toString()方法具有什么功能呢?
  • 猿创征文|Spring Boot日志
  • Blue Prism 异常处理
  • PCL 环境下安装配置CGAL 5.5
  • Code For Better 谷歌开发者之声——盘点大家用过的Google 产品
  • Android基本界面控件、部分属性方法解析
  • Qt5开发从入门到精通——第六篇二节( 图像与图片——基础图形的绘制 )
  • Hive学习笔记2
  • 【zabbix监控四】zabbix之监控tomcat服务报警案例
  • JavaScript endsWith() 方法
  • 软件测试(用例2)
  • C++11重写muduo网络库——预备知识
  • frp内网穿透—将kali代理在公网中进行渗透测试
  • php的引用
  • 【5+】跨webview多页面 触发事件(二)
  • 30秒的PHP代码片段(1)数组 - Array
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • MySQL数据库运维之数据恢复
  • TCP拥塞控制
  • 程序员该如何有效的找工作?
  • 大快搜索数据爬虫技术实例安装教学篇
  • 大主子表关联的性能优化方法
  • 动态魔术使用DBMS_SQL
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 前端_面试
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 异常机制详解
  • 选择阿里云数据库HBase版十大理由
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #HarmonyOS:软件安装window和mac预览Hello World
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)iOS字体
  • (转)关于pipe()的详细解析
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net Core缓存组件(MemoryCache)源码解析
  • .net core控制台应用程序初识
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET 表达式计算:Expression Evaluator
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .NET构架之我见
  • .NET命名规范和开发约定
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @ConfigurationProperties注解对数据的自动封装