创建时间:2020-7-16 17:04:36 更新时间:2020-7-16 17:04:41

静态代理

众所周知 Spring 的 AOP 是基于动态代理实现的,谈到动态代理就不得不提下静态代理。实现如下:

假设有一接口 InterfaceA:

  1. public interface InterfaceA{
  2. void exec();
  3. }

其中有实现类 RealImplement:

  1. public class RealImplement implement InterfaceA{
  2. public void exec(){
  3. System.out.println("real impl") ;
  4. }
  5. }

这时也有一个代理类 ProxyImplement 也实现了 InterfaceA:

  1. public class ProxyImplement implement InterfaceA{
  2. private InterfaceA interface ;
  3. public ProxyImplement(){
  4. interface = new RealImplement() ;
  5. }
  6. public void exec(){
  7. System.out.println("dosomethings before); //实际调用 interface.exec();
  8. System.out.println("dosomethings after);
  9. }
  10. }

使用如下:

  1. public class Main(){
  2. public static void main(String[] args){
  3. InterfaceA interface = new ProxyImplement() ;
  4. interface.exec();
  5. }
  6. }

可以看出这样的代理方式调用者其实都不知道被代理对象的存在。

JDK 动态代理

从静态代理中可以看出: 静态代理只能代理一个具体的类,如果要代理一个接口的多个实现的话需要定义不同的代理类。

需要解决这个问题就可以用到 JDK 的动态代理。

其中有两个非常核心的类:

  • java.lang.reflect.Proxy类。
  • java.lang.reflect.InvocationHandle接口。

Proxy 类是用于创建代理对象,而 InvocationHandler 接口主要你是来处理执行逻辑。

如下:

  1. public class CustomizeHandle implements InvocationHandler {
  2. private final static Logger LOGGER = LoggerFactory.getLogger(CustomizeHandle.class);
  3. private Object target;
  4. public CustomizeHandle(Class clazz) {
  5. try {
  6. this.target = clazz.newInstance();
  7. }
  8. catch (InstantiationException e) {
  9. LOGGER.error("InstantiationException", e);
  10. }
  11. catch (IllegalAccessException e) {
  12. LOGGER.error("IllegalAccessException",e);
  13. }
  14. }
  15. @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  16. before();
  17. Object result = method.invoke(target, args);
  18. after();
  19. LOGGER.info("proxy class={}", proxy.getClass());
  20. return result;
  21. }
  22. private void before() {
  23. LOGGER.info("handle before");
  24. }
  25. private void after() {
  26. LOGGER.info("handle after");
  27. }
  28. }

其中构造方法传入被代理类的类类型。其实传代理类的实例或者是类类型并没有强制的规定,传类类型的是因为被代理对象应当有代理创建而不应该由调用方创建。

使用方式如下:

  1. @Test
  2. public void test(){
  3. CustomizeHandle handle = new CustomizeHandle(ISubjectImpl.class) ;
  4. ISubject subject = (ISubject) Proxy.newProxyInstance(JDKProxyTest.class.getClassLoader(), new Class[]{
  5. ISubject.class
  6. }
  7. , handle);
  8. subject.execute() ;
  9. }

首先传入被代理类的类类型构建代理处理器。接着使用 ProxynewProxyInstance 方法动态创建代理类。第一个参数为类加载器,第二个参数为代理类需要实现的接口列表,最后一个则是处理器。

其实代理类是由这个方法动态创建出来的。将 proxyClassFile 输出到文件并进行反编译的话就可以的到代理类。

  1. @Test
  2. public void clazzTest(){
  3. byte[] proxyClassFile = ProxyGenerator.generateProxyClass("$Proxy1", new Class[]{ISubject.class}, 1);
  4. try {
  5. FileOutputStream out = new FileOutputStream("/Users/chenjie/Documents/$Proxy1.class") ;
  6. out.write(proxyClassFile);
  7. out.close();
  8. }
  9. catch (FileNotFoundException e) {
  10. e.printStackTrace();
  11. }
  12. catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }

反编译后结果如下:

  1. import com.crossoverjie.proxy.jdk.ISubject;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.lang.reflect.UndeclaredThrowableException;
  6. public class $Proxy1 extends Proxy implements ISubject {
  7. private static Method m1;
  8. private static Method m2;
  9. private static Method m3;
  10. private static Method m0;
  11. public $Proxy1(InvocationHandler var1) throws {
  12. super(var1);
  13. }
  14. public final Boolean equals(Object var1) throws {
  15. try {
  16. return ((Boolean)super.h.invoke(this, m1, new Object[]{
  17. var1
  18. }
  19. )).booleanValue();
  20. }
  21. catch (RuntimeException | Error var3) {
  22. throw var3;
  23. }
  24. catch (Throwable var4) {
  25. throw new UndeclaredThrowableException(var4);
  26. }
  27. }
  28. public final String toString() throws {
  29. try {
  30. return (String)super.h.invoke(this, m2, (Object[])null);
  31. }
  32. catch (RuntimeException | Error var2) {
  33. throw var2;
  34. }
  35. catch (Throwable var3) {
  36. throw new UndeclaredThrowableException(var3);
  37. }
  38. }
  39. public final void execute() throws {
  40. try {
  41. super.h.invoke(this, m3, (Object[])null);
  42. }
  43. catch (RuntimeException | Error var2) {
  44. throw var2;
  45. }
  46. catch (Throwable var3) {
  47. throw new UndeclaredThrowableException(var3);
  48. }
  49. }
  50. public final int hashCode() throws {
  51. try {
  52. return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
  53. }
  54. catch (RuntimeException | Error var2) {
  55. throw var2;
  56. }
  57. catch (Throwable var3) {
  58. throw new UndeclaredThrowableException(var3);
  59. }
  60. }
  61. static {
  62. try {
  63. m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{
  64. Class.forName("java.lang.Object")
  65. }
  66. );
  67. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  68. m3 = Class.forName("com.crossoverjie.proxy.jdk.ISubject").getMethod("execute", new Class[0]);
  69. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  70. }
  71. catch (NoSuchMethodException var2) {
  72. throw new NoSuchMethodError(var2.getMessage());
  73. }
  74. catch (ClassNotFoundException var3) {
  75. throw new NoClassDefFoundError(var3.getMessage());
  76. }
  77. }
  78. }

可以看到代理类继承了 Proxy 类,并实现了 ISubject 接口,由此也可以看到 JDK 动态代理为什么需要实现接口,已经继承了 Proxy是不能再继承其余类了。

其中实现了 ISubjectexecute() 方法,并通过 InvocationHandler 中的 invoke() 方法来进行调用的。

CGLIB 动态代理

cglib 是对一个小而快的字节码处理框架 ASM 的封装。他的特点是继承于被代理类,这就要求被代理类不能被 final 修饰。