SpringAOP原理:手写动态代理实现

0、基础知识

AOP我们知道,是在不修改源代码的情况下,为代码添加一些新功能的技术。通过动态代理,可以在不修改原始类代码的前提下,对方法进行拦截和增强。

动态代理常用于在不改变原有业务逻辑的情况下,对方法的调用进行额外的处理,比如日志记录、性能监控、事务管理等。它实现了面向切面编程(AOP)的核心概念。

1、动态代理

AOP其实就是先通过"一些办法"拿到"代理对象",再对这个代理对象添加新方法。

动态代理的两种办法:

1.1 JDK代理:基于接口的动态代理技术。

方法:通过目标接口,创建接口实现类,动态地 在运行时内存里生成代理对象,其拥有目标对象的原方法实现,最后通过代理对象来增加新功能。

看文字有些抽象,现在手动用代码实现一个JDK代理的AOP技术,根据jdk1.8手册找到Proxy类,通过newInstance方法实现动态代理对象的创建。

"**Proxy**提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。"

**(1)**准备接口和实现类

java 复制代码
//=========================接口============================
public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}

//=========================实现类============================
public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        System.out.println("add.......");
        return a+b;
    }
    @Override
    public String update(String id) {
        System.out.println("update===========");
        return id;
    }
}

(2) 创建UserDao的代理对象,调用增强方法

需要注意:InvocationHandler接口里有invoke方法必须实现,而调用代理对象的任何方法,实质都是在执行invoke方法

java 复制代码
public class JDKProxy {
    public static void main(String[] args) {
/**
newProxyInstance的三个内容:类加载器、要实现的接口的class、
和InvocationHandler(这是个接口,里面写的增强类的具体逻辑)
*/
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(
                JDKProxy.class.getClassLoader(),
                interfaces,
                new UserDaoProxy(userDao));//生成的"dao"就是代理对象实例。
        //也可以直接用匿名内部类的方法来写(new InvocationHandler)

        int add = dao.add(1, 2);//使用代理对象dao调用add的时候,无需改变add源码,却增强了功能。
        System.out.println("add=" + add);
    }
}

//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
    //把创建的是谁的代理对象,把谁传递过来
    //有参数构造传递
    private Object obj;//要创建obj的代理对象
    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }
    //增强的逻辑:InvocationHandler接口里有invoke方法必须实现
//调用代理对象的任何方法,实质都是在执行invoke方法。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前(增强)
        System.out.println("方法之前执行...."+method.getName()+" :传递的参数..." + Arrays.toString(args));
        //被增强的方法执行(原模块功能不变)
        Object res = method.invoke(obj, args);//res=3
        //方法之后(增强)
        System.out.println("方法之后执行...."+obj);
        return res;
    }
}

**但是有个遗留问题,**invoke函数究竟是如何被调用的,往下看了源码也没有分析出来,个人推测是这样的:

因为传入的obj其实就是要动态代理的原对象,但我们不知道具体执行什么方法,此时dao还未调用add方法。但调用了以后,invoke方法却能够自动调用、增强方法,内部应该是采用反射的方法,拿到"add"这个方法名称,通过getMethod反射出方法的类对象,再用method.invoke(具体对象)来实现方法的调用,从而调用add,并完成前后的增强。

1.2 cglib:基于父类的动态代理技术。

方法:为目标对象动态地生成子对象,其具有了父类的方法(实际不是继承)

实现类似,此处不做代码示例。

相关推荐
shayudiandian2 分钟前
【Java】注解
java
繁华似锦respect5 分钟前
C++ 设计模式之工厂模式详细介绍
java·linux·c++·网络协议·设计模式
零匠学堂20258 分钟前
OfficeOnlineServer文件在线浏览方案之OWA部署方法
开发语言·officeonline
想要成为祖国的花朵9 分钟前
基于多设计模式的抽奖系统__测试报告
java·selenium·测试工具·jmeter·设计模式·测试用例·安全性测试
未来之窗软件服务15 分钟前
幽冥大陆(三十六)S18酒店门锁SDK rust语言——东方仙盟筑基期
开发语言·c++·rust·智能门锁·东方仙盟sdk·东方仙盟一体化
m***l11529 分钟前
【Spring Boot】Spring AOP中的环绕通知
spring boot·后端·spring
v***56532 分钟前
常见的 Spring 项目目录结构
java·后端·spring
free-elcmacom35 分钟前
MATLAB物理仿真<1>电磁场有限元仿真
开发语言·matlab·电磁场仿真
Emilia486.37 分钟前
C++ 类与对象:解锁面向对象编程的核心密码(上)
开发语言·c++
超频化石鱼39 分钟前
使用Postman访问siliconflow大模型接口
java·postman·ai编程