【Spring】AOP动态代理

25 阅读2分钟

新手小白记录跟着狂神学Spring的过程(第19集)~

1. 浅谈AOP

AOP(面向切面编程)的底层就是动态代理,它把「通用的额外操作」(例如日志、事务、权限)抽成切面(Aspect),然后通过动态代理,自动把切面逻辑织入到业务方法中。

2. 代理调用处理程序类

作用:可以通过这个类自动生成一个代理类。

这个类实现了InvocationHandler接口,其中,最关键的方法是invoke(),这个方法在调用代理方法时执行,可以把日志等需要处理的方法放在invoke()里面。这样,当调用代理方法时,也会执行日志记录这个方法。并且,invoke 是 JVM 自动调用的:你不用手动写 handler.invoke(...),JVM 会帮你做这个动作,这也是动态代理的核心便捷性。

public class ProxyInvocationHandler implements InvocationHandler{
  //被代理的对象
  private Object target;  

  public void setTarget(Object target){
    this.target = target;
  }

  // 生成代理实例
  public Object getProxy(){
    return Proxy.newProxyInstance(
            this.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
        );
  }

  // invoke方法:这里是代理逻辑的定义,可以在这里加上打印日志等方法
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      log(method.getName());
      Object result = method.invoke(target, args);
      return result;
  }

  // 打印日志
  public void log(String msg){
    System.out.println("执行了" + msg + "方法");
  }

3. 如何动态生成代理类

@Test
public void test(){
    // 被代理的角色
    UserService userService = new UserServiceImpl();

    // 等会要用代理调用处理程序动态生成代理类
    ProxyInvocationHandler pih = new ProxyInvocationHandler();

    // 设置要代理的对象
    pih.setTarget(userService);

    //动态生成代理类
    UserService proxy = (UserService)pih.getProxy();

    //调用代理方法
    proxy.add();
    
}

4.JDK动态代理代理的是接口

由于Java 的语法规则是:一个类只能有一个直接父类(单继承)。既然代理类已经继承了 Proxy,就无法再继承目标类(比如 UserServiceImpl)—— 只能通过「实现目标类的接口」(比如 UserService),来和目标对象建立方法关联。

JDK 动态代理的核心方法 Proxy.newProxyInstance,必须传入目标对象的接口数组(Class<?>[] interfaces),底层会根据这些接口生成代理类的字节码:

  • 代理类会implements这些接口,并重写接口中的所有方法;
  • 重写后的方法内部,会调用 InvocationHandlerinvoke 方法。

所以,jdk的代理对象是一个接口。

参考视频:19、动态代理详解_哔哩哔哩_bilibili