Java 基础 动态代理

231 阅读4分钟

动态代理:

代理:这个概念是什么呢,比如我们交话费,交话费交给谁呢,这个收钱的是不是中国的三大运营商,但是我们普通人怎么去充值话费呢,这时我们是不不是需要去营业厅去交话费,营业厅输入我们的电话号码,和我们的金额,在运营商的账户中一充值我们手机就能够接收到了余额的信息了。这个充话费的过程就是属于代理,营业厅代理了我们去充值。

[sfFyB8.png]( 这个过程产生的代码如下面所示


/**
 * 定义个人的接口,
 * 就比如人交话费
 */
public interface Person {
    public void payBill();
}


//定义用户
public class User implements Person{
    @Override
    public void payBill() {
        // 用户没有时间,不知道其他方式充值
        System.out.println("充值移动号码话费:50元");
    }
}




/**
 * 代理商帮助用户充值
 */
public class Operators implements Person{
    private User user;
    public Operators(User user){
        this.user = user;
    }
    @Override
    public void payBill() {
        System.out.println("营业厅充值话费");
        this.user.payBill();
        System.out.println("充值成功");
    }

    public static void main(String[] args){
        Operators operators = new Operators(new User());
        operators.payBill();
    }
}
/**
 * ~out
 * 营业厅充值话费
 * 充值移动号码话费:50元
 * 充值成功
 */

上面就是整个静态代理的过程以及实现,下面来看动态代理。

动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象)

(Using Java Reflection to create dynamic implementations of interfaces at runtime)。

代理的是接口(Interfaces),不是类(Class),更不是抽象类。

解决特定问题:一个接口的实现在编译时无法知道,需要在运行时才能实现

实现某些设计模式:适配器(Adapter)或修饰器(Decorator)

其实个人感觉在适配器方面和Aop中使用的动态代理还挺多的,个人感觉还是不太清晰,只是其中通过反射获取接口中的实现类通过Handler中持有的代理的实例target然后所有代理对象的方法都会通过invoke方法执行,

interface Person {
    void walk();
    void sayHello(String name);
}

class MyInvokationHandler implements InvocationHandler {
/*
执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
其中:
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表调用目标方法时传入的实参
*/
    public Object invoke(Object proxy, Method method, Object[] args) {
        System.out.println("----正在执行的方法:" + method);
        if (args != null) {
            System.out.println("下面是执行该方法时传入的实参为:");
            for (Object val : args) {
                System.out.println(val);
            }
        } else {
            System.out.println("调用该方法没有实参!");
        }
        return null;
    }

}

public class ProxyTest {

    public static void main(String[] args)

            throws Exception {

// 创建一个InvocationHandler对象
        InvocationHandler handler=new MyInvokationHandler();
        // 使用指定的InvocationHandler来生成一个动态代理对象
        Person p=(Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler); // 调用动态代理对象的walk()和sayHello()方法
        p.walk();
        p.sayHello("孙悟空");
    }

}
public class Test {
    /**
     * JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合,入口是Proxy。
     * Proxy有个静态方法:getProxyClass(ClassLoader, interfaces),只要你给它传入类加载器和一组接口,它就给你返回代理Class对象。
     */
    public static void  main(String[] args){
        // 创建一个程序员
        Programmer programmer = new Programmer();
        // 创建kay  bos
        Person kayProgrammer = new KayProgrammer(programmer);
        // kay bos 让程序员替写代码
        kayProgrammer.doJob();
        // 用program生成一个代理对象
        Person programmerdoJob = (Person) Proxy.newProxyInstance(programmer.getClass().getClassLoader(), programmer.getClass().getInterfaces(), (proxy, method, args1) -> {
            System.out.println("----执行方法"+method);
            // 如果调用了doJob方法
            if(args!=null){
                System.out.println("下面是执行该方法时传入的实参为:");
                for (Object val : args) {
                    System.out.println(val);
                }
                method.invoke(kayProgrammer,args);
            }else{
                System.out.println("调用该方法没有实参!");
            }
            return null;
        });

        programmerdoJob.doJob();
    }


}

interface Person{
    // 人干活
    void  doJob();
}

class Programmer implements  Person{

    @Override
    public void doJob() {
        System.out.println("程序员的工作是写代码");
    }
}
// 这个KayProgrammer是个不写代码的公司的leader.
class KayProgrammer implements Person {

    // 让程序员去写
    private Programmer programmer;

    public KayProgrammer(Programmer programmer) {
        this.programmer = programmer;
    }
    // 这个KayProgrammer程序员写代码让自己看
    public void notice(){
        System.out.println("notice.... coding to me");
    }
    @Override
    public void doJob() {
        System.out.println("我是kay 我不想写代码 我让程序员去写");
        // 让程序员写代码
        programmer.doJob();
        // 自己看代码
        notice();
    }
}

这样以来动态代理就清晰了许多,那么我们来模仿者JDK动态代理手写一个属于自己的动态代理 jdk动态代理生成对象的步骤如下以后再写:

1.获取被代理对象的引用,并且获取它所有的接口,反射获取

2.JDK动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口

3.动态生成java代码,新加的业务逻辑方法有一定的逻辑代码调用(在代码中体现)

4.编译新生成的Java代码.class文件

5.重新加载到JVM中运行。