【SpringAOP】——JDK动态代理

「爱情、让人受尽委屈。」 2022-07-18 05:09 277阅读 0赞
  1. Spring的动态代理有两种:一是JDK的动态代理(需要提供接口);另一个是cglib动态代理(通过修改字节码来实现代理)。大部分情况下,一般使用JDK动态代理,因为JDK动态代理的速度要比CGLIB要快,在SpringAOP中,如果一个Bean有接口声明,那么Spring就会使用JDK动态代理代理它,否则启用CGLIB。今天咱们主要讨论JDK动态代理的方式。JDK的代理方式主要就是通过反射跟动态编译来实现的。
  2. 反射上一篇文章已经说过了([Java反射][Java]),这里就不在做论述。我们先了解一下动态代理。
  3. 假如,A是一个软件工程师,A所在的公司是一个软件公司。现在,B为客户,B需要A所在的软件公司开发一款软件。显然,B需要找的是A公司的商务,跟商务进行沟通。最终,软件的开发由A来落实。在这里边,A公司的商务就相当于一个代理。代理的实际就是在真实服务对象(A)之前,加一个代理对象(商务)。这个代理对象,可以根据调用者(B)的要求去控制真实服务对象(A)的访问。
  4. 代理模式的好处:可以增加一些服务,同时可以根据需要选择是否需要启用真实服务对象。

579c01c50001842109610301.jpg

扯了半天,下边进入正题,JDK动态代理

需要提供一个简单的接口

  1. public interface HelloService
  2. {
  3. public void sayHello(String name);
  4. }

实现类

  1. public class HelloServiceImpl implements HelloService
  2. {
  3. @Override
  4. public void sayHello(String name)
  5. {
  6. System.err.println("hello " + name);
  7. }
  8. }

接着,需要生成代理对象(proxy),分成两步:

1.生成代理对象需要建立代理对象(proxy)和真实对象(HelloServiceImpl)的代理关系

2.实现代理方法

在JDK动态代理中需要实现接口:java.lang.reflect.InvocationHandler.

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. public class HelloProxy implements InvocationHandler
  5. {
  6. private Object target;
  7. /**
  8. * 生成代理对象,并和真实服务对象绑定.
  9. * @param target 真实服务对线下
  10. * @return 代理对象 */
  11. public Object bind(Object target)
  12. {
  13. this.target = target;
  14. //生成代理对象,并绑定.
  15. Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //类的加载器
  16. target.getClass().getInterfaces(), //对象的接口,明确代理对象挂在哪些接口下
  17. this);//指明代理类,this代表用当前类对象,那么就要求其实现InvocationHandler接口的invoke方法
  18. return proxy;
  19. }
  20. /**
  21. * 当生成代理对象时,第三个指定使用HelloProxy进行代理时,代理对象调用的方法就会进入这个方法。
  22. * @param proxy ——代理对象
  23. * @param method -- 被调用的方法
  24. * @param args -- 方法参数
  25. * @return 代理方法返回。
  26. * @throws Throwable -- 异常处理 */
  27. @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  28. {
  29. System.err.println("反射真实对象方法前");
  30. Object obj = method.invoke(target, args);//相当于sayHello方法调用.
  31. System.err.println("反射真实对象方法后");
  32. return obj;
  33. }
  34. }

说明一下上边的代码:

首先声明了一个类的属性target,它的作用是保存真实服务对象(B);然后用bind方法绑定代理对象(proxy商务)和真实对象(A)。

用之前的比喻就是proxy就是商务,它代理了target(A),而商务代理的逻辑方法放在this这个对象的invoke方法中,只是this这个对象需要实现InvocationHandler接口而已。这样,声明就会进入当前类的invoke方法中,它实现的是代理逻辑,它有三个参数

Object proxy——当前代理对象(商务)

Method method——当前调度的方法

Object[] args——方法参数

然后我们通过反射调度真实对象的方法,Object obj = method.invoke(target, args);//相当于sayHello方法调用,实现功能。

控制台进行打印

  1. public class Chapter1Main
  2. {
  3. public static void main(String[] args)
  4. {
  5. HelloProxy helloProxy = new HelloProxy();
  6. //因为使用了接口HelloService绑定了代理对象,所以可以用HelloService作为代理对象的声明.
  7. HelloService proxy = (HelloService) helloProxy.bind(new HelloServiceImpl());
  8. proxy.sayHello("张三");//此时使用代理对象运行方法进入HelloProxy的invoke方法里
  9. }
  10. }

打印出来的结果

  1. 反射真实对象方法前
  2. hello 张三
  3. 反射真实对象方法后

至此,HelloService实际上已经是一个代理对象了。

发表评论

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

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

相关阅读

    相关 代理-jdk动态代理

    1、基于接口的实现,要jdk动态代理的类必须要实现一个接口; 2、中介类:实现了InvocationHandler,并重写这个接口的 方法(public Object inv