动态代理

动态代理

Posted by bulingfeng on July 27, 2024

简介

代理分为两种,一种是静态代理,一种是动态代理。

静态代理:在编译的时候生成代理类的字节码;

动态代理:在程序运行的过程中生成代理类的字节码;

使用静态代理的时候,需要有个代理类和原来要加强的逻辑都有同样的接口,然后代理类通过实现接口来对想要操作的方法进行加强。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IUserController {
  UserVo login(String telephone, String password);
  UserVo register(String telephone, String password);
}

public class UserController implements IUserController {
  @Override
  public UserVo login(String telephone, String password) {
    //...省略逻辑...
  }

  @Override
  public UserVo register(String telephone, String password) {
    //...省略逻辑...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class UserControllerProxy implements IUserController {
  private static final Logger logger = LoggerFactory.getLogger(UserControllerProxy.class);
  private UserController userController;

  public UserControllerProxy(UserController userController) {
    this.userController = userController;
  }

  @Override
  public UserVo login(String telephone, String password) {
    long startTime = System.currentTimeMillis();
    UserVo userVo = userController.login(telephone, password);
    long costTime = System.currentTimeMillis() - startTime;
    logger.info("UserController#login cost time:" + costTime);
    return userVo;
  }

  @Override
  public UserVo register(String telephone, String password) {
    long startTime = System.currentTimeMillis();
    UserVo userVo = userController.register(telephone, password);
    long costTime = System.currentTimeMillis() - startTime;
    logger.info("UserController#register cost time:" + costTime);
    return userVo;
  }
}

JDK的动态代理

关键重点(其实就是通过反射把对应的类和方法加载到JVM,然后再通过反射来调用对应类的方法)

  • 必须要求原始类是有接口定义才行。
  • 实现InvocationHandler接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class CtrlProxyHandler implements InvocationHandler {
  private Object origBean;

  public CtrlProxyHandler(Object origBean) {
    this.origBean = origBean;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    long startTime = System.currentTimeMillis();
    Object res = method.invoke(origBean, args);
    long costTime = System.currentTimeMillis() - startTime;
    System.out.println(origBean.getClass().getSimpleName() + "#"
        + method.getName() + " cost time: " + costTime);
    return res;
  }
}

public class JDKProxyDemo {
  public static void main(String[] args) {
    IUserController userController = new UserController();
    CtrlProxyHandler handler = new CtrlProxyHandler(userController);
    IUserController userControllerProxy = (IUserController) Proxy.newProxyInstance(
        handler.getClass().getClassLoader(), UserController.class.getInterfaces(), handler);
    userControllerProxy.login("139********", "******");
  }
}

CGLIB实现动态代理

关键点

  • 需要引入cglib的包
  • 实现MethodInterceptor接口
  • 原始类是一个类,无需是接口
  • Enhancer的使用