关于java动态代理的实现

动态代理主要解决一个问题:面向切面编程aop

如:日志、探针监控/mybatis的实现原理

动态代理原理一句话描述:

首先需要依赖一个interface,然后需要一个增强器hander,然后需要一个proxy根据素材去动态的实现这个接口。

  • interface:是动态代理的对象
  • hander:是怎么样去增强这个代理对象被调用的方法。
  • proxy:是一个调度,告诉JVM在运行期动态用什么素材(interface和hander等)创建实现类的class字节码并加载的过程,以供调用,默认是注入到内存里面,不生成具体的.class文件(可以修改配置参数让其生成)

直接上demo

->接口类

package com.example.demo.proxy;

public interface Animal {

    void eat(String s);
}

->实现类

package com.example.demo.proxy;

public class Cat implements Animal {
    public void eat(String s) {
        System.out.println("hello world");
    }
}

->增强handler

package com.example.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Handler implements InvocationHandler {
    private Animal animal;

    public Handler() {
        super();
    }

    public Handler(Animal animal) {
        super();
        this.animal = animal;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.printf("前置增强\n");
        System.out.printf(method.getName() + " " + args[0]+"\n");
        if (this.animal != null) {
            method.invoke(animal, args);
        }

        System.out.printf("后置增强\n==========================\n");
        return null;
    }
}

->测试

package com.example.demo.proxy;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) throws NoSuchMethodException {

        //接口类的动态代理,让接口也可以实例化并调用接口方法并实现方法增强
        InvocationHandler handler1 = new Handler();

        Animal proxy1 = (Animal) Proxy.newProxyInstance(
                Animal.class.getClassLoader(),
                new Class[] { Animal.class }, 
                handler1); 
        proxy1.eat("meat");
        
        //实现类的动态代理并实现方法增强
        Animal animal = new Cat();
        InvocationHandler handler2 = new Handler(animal);

        Animal proxy2 = (Animal) Proxy.newProxyInstance( 
                Animal.class.getClassLoader(), // 传入ClassLoader,确定要用哪个加载器来加载.class
                new Class[] { Animal.class }, // 传入要实现的接口,这里也意味这这种方式,只能支持接口或者实现类的动态代理。
                handler2); // 传入处理调用方法的InvocationHandler,核心方法,在实例化这个接口的时候,重写类方法,用来增强类方法的逻辑依据。
                //如果hander里面没有传入接口的实例,则只增强这个空的接口方法。例如mybatis的动态代理,实现dao接口层和mapper.xml的绑定。
                //如果hander里面有传入接口的实例,则可以在这个增强逻辑里面调用这个实例方法,实现aop注入。
proxy2.eat("meat"); } }

->结果

 

posted @ 2021-04-27 01:20  zenghansen  阅读(152)  评论(0编辑  收藏  举报