AOP之jdk动态代理

16 阅读2分钟

动态代理主要是解耦与增强,将抽象与实现进行解耦,对已有的实现进行增强。

有目标类,对目标类进行额外的业务增强,没有目标类,就抽象与实现解耦。

java动态代理可以对接口实现的非final方法进行AOP切面增强。

    // 接口
public interface UserService {
    void saveUser(String name);
}

// 目标类【不是必须的,可以只要代理实现】
public class UserServiceImpl implements UserService {
    public void saveUser(String name) {
        System.out.println("保存用户: " + name);
    }
}

// InvocationHandler实现
public class LogHandler implements InvocationHandler {
    private Object target;

    public LogHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前: " + method.getName());
        Object result = method.invoke(target, args); // 调用目标方法【不是必须的,可以只要代理实现】
        System.out.println("方法调用后");
        return result;
    }
}

// 使用动态代理
public class Main {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();//【不是必须的,可以只要代理实现】
        UserService proxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                new Class[]{UserService.class},
                new LogHandler(realService)
        );
        proxy.saveUser("Alice"); // 输出增强后的逻辑
    }
}

Java动态代理通过运行时生成字节码实现接口代理,将方法调用转发至InvocationHandler,从而解耦业务逻辑(接口与目标类是早期业务模块代码)与横切关注点(InvocationHandler实现类切点业务关注点)。其核心在于Proxy类的字节码生成与类加载机制,结合反射实现灵活的方法增强。尽管存在性能开销和仅支持接口的局限,但在多数场景下仍为AOP和动态扩展的首选方案。
    public final class $Proxy0 extends Proxy implements Subject {
        // 静态方法表:缓存接口方法对应的Method对象
        private static Method m1;  // hashCode()
        private static Method m2;  // equals()
        private static Method m3;  // toString()
        private static Method m4;  // 接口方法doSomething()

        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("hashCode");
                m2 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m3 = Class.forName("java.lang.Object").getMethod("toString");
                m4 = Class.forName("Subject").getMethod("doSomething");
            } catch (Exception e) { /* 异常处理 */ }
        }

        // 构造函数:传入InvocationHandler
        public $Proxy0(InvocationHandler h) {
            super(h);  // Proxy的构造方法设置handler
        }

        // 接口方法实现
        @Override
        public final void doSomething() {
            try {
                super.h.invoke(this, m4, null);  // 调用handler.invoke()
            } catch (Throwable e) { /* 异常处理 */ }
        }

        // Object方法重写(如hashCode、equals、toString)
        @Override
        public final int hashCode() { 
            return (int) super.h.invoke(this, m1, null); 
        }
    }
    
   通过配置 -Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true 可以查看生成的代码
    +-----------+     +----------+     +----------------+     +---------------+     +------------------+
    |  Client   |     |  Proxy   |     | ProxyGenerator |     | ClassLoader   |     |    $Proxy0       |
    +-----------+     +----------+     +----------------+     +---------------+     +------------------+
          |                 |                   |                     |                     |
          |--1: newProxyInstance()------------->|                     |                     |
          |                 |                   |                     |                     |
          |                 |--2: getProxyClass0()------------------->|                     |
          |                 |                   |                     |                     |
          |                 |<--3: 检查缓存是否存在-------------------|                     |
          |                 |                   |                     |                     |
          |                 |--4: 缓存未命中,生成新代理类------------>|                     |
          |                 |                   |                     |                     |
          |                 |                   |--5: generateProxyClass()----------------->|
          |                 |                   |                     |                     |
          |                 |                   |<--6: 生成字节码byte[]---------------------|
          |                 |                   |                     |                     |
          |                 |--7: defineClass()---------------------->|                     |
          |                 |                   |                     |                     |
          |                 |<--8: 加载$Proxy0类----------------------|                     |
          |                 |                   |                     |                     |
          |                 |--9: 缓存代理类------------------------->|                     |
          |                 |                   |                     |                     |
          |                 |--10: 实例化$Proxy0(newInstance())------>|                     |
          |                 |                   |                     |                     |
          |<--11: 返回$Proxy0实例-------------------------------------|                     |
          |                 |                   |                     |                     |
      ```
      
      
     ```通过生成的代理对象调用方法
     Client           $Proxy0         InvocationHandler        UserServiceImpl
      |                |                     |                        |
      |--doSomething()->|                     |                        |
      |                |---invoke()---------->|                        |
      |                |                     |----target.doSomething()->|
      |                |                     |<-----------return--------|
      |                |<-------return--------|                        |
      |<--return--------|                     |                        |
    ```