设计模式之 代理模式下 动态代理

静态代理有一个问题就是,如果被代理的目标类非常多,那我们就要生成非常多的代理类,比如我们上一节的例子中,我要记录性能的类,如果有100+个,那我就要再写100多个代理类,这显然是不合理的。

这是动态代理就登场了。

动态代理就是不用事先为每一个被代理的目标类,一一生成代理类,而是在运行时,按照需要动态生成代理类,来完成代理工作。

Java本身就实现了动态代理功能,其原理是基于反射实现的。

我们来看一下上一节的静态代理,如何演变为动态代理。

1、定义抽象用户类

package com.my.study.design.proxy.dynamic;

/**
 * www.itzhimei.com
 */
public interface IUser {

    void business() throws InterruptedException;
}

2、定义具体用户类,实现抽象用户类

package com.my.study.design.proxy.dynamic;


/**
 * www.itzhimei.com
 */
public class User implements IUser {

    @Override
    public void business() throws InterruptedException {
        System.out.println("用户类输出:执行业务方法计算中....");
        Thread.sleep(500L);
        System.out.println("用户类输出:执行业务方法计算完成");
    }
}

3、定义动态代理的业务处理类,也就是代理的处理逻辑,要写在这里

package com.my.study.design.proxy.dynamic;

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


/**
 * www.itzhimei.com
 */
public class DynamicProxy implements InvocationHandler {

    private Object realObject;

    public DynamicProxy(Object realObject) {
        this.realObject = realObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理输出:前置业务方法计算中....");
        method.invoke(realObject,args);
        System.out.println("动态代理输出:附加业务方法计算中....");
        return null;
    }
}

Java的动态代理API要求动态代理的代理处理逻辑,要实现InvocationHandler接口,覆写invoke()方法。这里就相当于静态代理中我们分别实现了login方法和business()方法。

4、测试

import java.lang.reflect.Proxy;

/**
 * www.itzhimei.com
 */
public class Client {

    public static void main(String[] args) throws InterruptedException {
        User user = new User();
        DynamicProxy handler = new DynamicProxy(user);
        IUser u = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),handler);
        u.business();

    }
}

这里的一个重要方法就是Proxy.newProxyInstance(),这是生成动态代理的类和方法。

5、输出

动态代理输出:前置业务方法计算中....
用户类输出:执行业务方法计算中....
用户类输出:执行业务方法计算完成
动态代理输出:附加业务方法计算中....

我们看到,动态代理的输出日志和handle中定义的invoke是一致的,在实际的业务方法之前和之后执行。