如何实现JDK动态代理?

秒速五厘米 2022-06-15 12:19 257阅读 0赞

代理模式:

代理模式给某个对象提供了一个代理对象,并由代理对象控制对原对象的引用。

代理分为静态代理和动态代理。

为何用代理?

不用代理时,在写实现接口类UserManagerImpl的时候代码是这样写的:

  1. public void addUser(String userId, String userName) {
  2. System.out.println("start-->>addUser() userId-->>" + userId);
  3. try {
  4. System.out.println("UserManagerImpl.addUser() userId-->>" + userId);
  5. System.out.println("success-->>addUser()");
  6. }catch(Exception e) {
  7. e.printStackTrace();
  8. System.out.println("error-->>addUser()");
  9. throw new RuntimeException();
  10. }
  11. }

我们的需求是调用每个像addUser()这样的方法都需要加上日志记录,开始需要记录,成功需要记录,错误也需要记录,这样如果该类中方法很多的话,在维护的时候就会很难,为了遵守OCP,我们索性抽出一个代理类,代真正的实现类去执行一些操作,所以就用到了代理模式。

第一版重构:

使用静态代理:
调用流程图:
这里写图片描述

代理类部分代码实现:

  1. public class UserManagerImplProxy implements UserManager {
  2. private UserManager userManager;
  3. public UserManagerImplProxy(UserManager userManager) {
  4. this.userManager = userManager;
  5. }
  6. public void addUser(String userId, String userName) {
  7. try {
  8. System.out.println("start-->>addUser() userId-->>" + userId);
  9. userManager.addUser(userId, userName);
  10. System.out.println("success-->>addUser()");
  11. }catch(Exception e) {
  12. e.printStackTrace();
  13. System.out.println("error-->>addUser()");
  14. }
  15. }
  16. }

静态代理解决了OCP的问题,但同样存在其他问题:
1、如果系统足够大,需要建立大量的代理类
2、重复代码出现在各个地方,违背原则:重复代码最好不要出现多次。

第二版重构:

使用动态代理:
调用流程图:
这里写图片描述

代码实现:
Client类:

  1. public static void main(String[] args) {
  2. LogHandler logHandler = new LogHandler();
  3. //userManager是一个代理对象
  4. UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
  5. //userManager.addUser("0001", "张三");
  6. //userManager.delUser("0001");
  7. String name = userManager.findUser("0001");
  8. System.out.println("Client.main() --- " + name);
  9. }

LogHandler类:

  1. public class LogHandler implements InvocationHandler {
  2. private Object targetObject;
  3. //this相当于一个代理对象
  4. public Object newProxyInstance(Object targetObject) {
  5. this.targetObject = targetObject;
  6. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
  7. targetObject.getClass().getInterfaces(), this);
  8. }
  9. //每次调用该方法都会动态添加日志记录
  10. public Object invoke(Object proxy, Method method, Object[] args)
  11. throws Throwable {
  12. System.out.println("start-->>" + method.getName());
  13. for (int i=0; i<args.length; i++) {
  14. System.out.println(args[i]);
  15. }
  16. Object ret = null;
  17. try {
  18. //调用目标方法,方法有返回值,ret不为空;方法无返回值,ret默认null;该method为findUser(),根据Client传过来,动态识别
  19. ret = method.invoke(targetObject, args);
  20. System.out.println("success-->>" + method.getName());
  21. }catch(Exception e) {
  22. e.printStackTrace();
  23. System.out.println("error-->>" + method.getName());
  24. throw e;
  25. }
  26. return ret;
  27. }
  28. }

动态代理:在运行时创建代理类,JDK动态代理只能对实现了接口的类进行代理,意思是,用LogHandler代理UserManagerImpl,前提是UserManagerImpl必须实现UserManager接口。

cglib代理

如果没有实现接口,就要用到cglib代理了

  1. public class CglibProxy implements MethodInterceptor {
  2. private Enhancer enhancer = new Enhancer();
  3. public Object getProxy(Class<?> clazz) {
  4. enhancer.setSuperclass(clazz);
  5. enhancer.setCallback(this);
  6. Object object = enhancer.create();
  7. return object;
  8. }
  9. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  10. System.out.println(o.getClass().getName() + "." + method.getName());
  11. //执行父类对应方法
  12. final Object result = methodProxy.invokeSuper(o, objects);
  13. System.out.println("执行结束");
  14. return result;
  15. }
  16. public static void main(String[] args) {
  17. CglibProxy proxy = new CglibProxy();
  18. Person person = (Person) proxy.getProxy(Person.class);
  19. System.out.println(person.getClass().getName());
  20. person.study();
  21. }
  22. }

比较静态代理和动态代理

这里写图片描述

动态代理:实现JDK里的InvocationHandler接口得invoke(),但注意的是代理的接口,也就是你的业务必须实现接口,通过Proxy的newProxyInstance得到代理对象。

感谢您的阅读!

发表评论

表情:
评论列表 (有 0 条评论,257人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JDK动态代理实现原理

    之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白。比如说:InvocationHandler的invoke方法是由谁来调用的,代理对象是怎么生成的,直到前几个星期才把

    相关 如何实现JDK动态代理

    代理模式: 代理模式给某个对象提供了一个代理对象,并由代理对象控制对原对象的引用。 代理分为静态代理和动态代理。 为何用代理? 不用代理时,在写实现接口类Use

    相关 jdk动态代理实现

    说jdk动态代理模式,先来说一下什么是代理模式,顾名思义,就是别人需要做的活让其他人代理做了。比较常见的是,我需要买火车票,我现在没有办法去火车站购买,找到离我最近的火车票代理