JDK 动态代理

Jdk动态代理的原理:被代理对象实现某个接口(前提),代理对象拦截被代理对象的方法调用,在其中可以全然抛弃被代理对象的方法实现而完成另外的功能,也可以在被代理对象方法调用的前后增加一些额外的功能。

动态代理的核心是生成代理对象,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。

  • ClassLoader,用于加载代理类的 Loader 类,通常这个 Loader 和被代理的类是同一个 Loader 类。
  • Interfaces,是要被代理的那些那些接口。
  • InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。
Person zhangsan = new Student("张三");                                          
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
 new Class[]{Person.class}, 
new StuInvocationHandler(zhangsan));

//通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类

Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});

//通过实现InvocationHandler接口创建调用处理器 

IvocationHandler handler = new InvocationHandlerImpl(...);

//通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型

Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

//通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入

Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

//

ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
JD-GUI这样的反编译软件打开jre\lib\rt.jar来一探究竟,以下是其核心代码的分析。 

//添加接口中定义的方法,此时方法体为空  

for (int i = 0; i < this.interfaces.length; i++) {  

  localObject1 = this.interfaces[i].getMethods();  

  for (int k = 0; k < localObject1.length; k++) {  

     addProxyMethod(localObject1[k], this.interfaces[i]);  

  }  

}  

//添加一个带有InvocationHandler的构造方法  

MethodInfo localMethodInfo = new MethodInfo("""(Ljava/lang/reflect/InvocationHandler;)V"1);  

//循环生成方法体代码(省略)  

//方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略)  

this.cp.getInterfaceMethodRef("InvocationHandler""invoke""Object; Method; Object;")  

//将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。  

localFileOutputStream = new FileOutputStream(ProxyGenerator.access$000(this.val$name) + ".class");  

localFileOutputStream.write(this.val$classFile);

 

Proxy 接口

Proxy 的主要静态变量

1

2

3

4

5

6

7

8

9

10

11

12

13

// 映射表:用于维护类装载器对象到其对应的代理类缓存

private static Map loaderToCache = new WeakHashMap();

// 标记:用于标记一个动态代理类正在被创建中

private static Object pendingGenerationMarker = new Object();

// 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断

private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());

// 关联的调用处理器引用

protected InvocationHandler h;

Proxy的构造方法

// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用

private Proxy() {}

// 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用

protected Proxy(InvocationHandler h) {this.h = h;}

ProxySubject 源码

创建的代理类 ProxySubject.class

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

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

import java.lang.reflect.*;  

public final class ProxySubject extends Proxy  implements Subject{  

    private static Method m1;  

    private static Method m0;  

    private static Method m3;  

    private static Method m2;  

    public ProxySubject(InvocationHandler invocationhandler){  

        super(invocationhandler);  

    }  

    public final boolean equals(Object obj){  

        try {  

            return ((Boolean)super.h.invoke(this, m1, new Object[] {  

                obj  

            })).booleanValue();  

        }catch(Error _ex) {

        }catch(Throwable throwable){  

            throw new UndeclaredThrowableException(throwable);  

        }  

    }  

    public final int hashCode()   { 

        try  {  

            return ((Integer)super.h.invoke(this, m0, null)).intValue();  

        }catch(Error _ex) {

        }catch(Throwable throwable){  

            throw new UndeclaredThrowableException(throwable);  

        }  

    }  

    /*关键部分*/

    public final void doSomething()  {  

        try {  

            // Proxy类中protected InvocationHandler h;关联的调用处理器引用

            super.h.invoke(this, m3, null);  

            return;  

        }catch(Error _ex) {  

        }catch(Throwable throwable) {  

            throw new UndeclaredThrowableException(throwable);  

        }  

    }  

    public final String toString() {  

        try {  

            return (String)super.h.invoke(this, m2, null);  

        catch(Error _ex) {

        catch(Throwable throwable){  

            throw new UndeclaredThrowableException(throwable);  

        }  

    }  

    static{  

        try {  

            m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] {  

                Class.forName("java.lang.Object")  

            });  

            m0 = Class.forName("java.lang.Object").getMethod("hashCode"new Class[0]);  

            m3 = Class.forName("Subject").getMethod("doSomething"new Class[0]);  

            m2 = Class.forName("java.lang.Object").getMethod("toString"new Class[0]);  

        }catch(NoSuchMethodException nosuchmethodexception)   {  

            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  

        }catch(ClassNotFoundException classnotfoundexception){  

            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  

        }  

    }  

}

CGLib 动态代理

动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。

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

28

29

public static void main(String[] args) {  

    byteCodeGe();  

}  

public static void byteCodeGe() {  

    //创建一个织入器  

    Enhancer enhancer = new Enhancer();  

    //设置父类  

    enhancer.setSuperclass(Business.class);  

    //设置需要织入的逻辑  

    enhancer.setCallback(new LogIntercept());  

    //使用织入器创建子类  

    IBusiness2 newBusiness = (IBusiness2) enhancer.create();  

    newBusiness.doSomeThing2();  

}  

/** 

 * 记录日志 

 */  

public static class LogIntercept implements MethodInterceptor {  

    @Override  

    public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {  

        //执行原有逻辑,注意这里是invokeSuper  

        Object rev = proxy.invokeSuper(target, args);  

        //执行织入的日志  

        if (method.getName().equals("doSomeThing2")) {  

            System.out.println("记录日志");  

        }  

        return rev;  

    }  

}

你可能感兴趣的:(java,动态代理)