Java设计模式之静态代理和动态代理

代理模式要用定义的方式描述可能要写一大串,简单的描述一下把。比如说一个班级有40个学生,一个班上,一个老师,学生开学要交学费,不可能一个个学生跑到老师面前交学费吧。说大一点,全校学生要交学费,不可能所有人跑到校长面前交学费吧。这个时候代理模式孕育而生,班级中可以选取班长作为代理者收取班上学生的学费,然后上交给老师,然后老师可以做为学生的代理者将学费交到学校,这样一说是不是要简单理解一点了。

下面放个图,大家理解理解吧。

代理模式
下面我将从两个demo来对静态代理和动态代理来进行总结学习。
首先静态代理的demo很好写,也很好理解。
首先创建Person接口

/**
 * 创建Person接口
 * @author Jet
 */
public interface Person {
    void giveMoney();//上交学费
}

然后用学生类实例化Person接口

public class Student implements Person{
    private String name;
    public Student(String name){
        this.name = name;
    }
    @Override
    public void giveMoney() {
        System.out.println(name + "上交学费10000");
    }
}

然后写一个学生代理类,来代理学生完成交学费的任务。

/**
 *学生代理类,实现了Person接口,保存一个学生实体,这样可以代理学生产生行为
 *@author Jet
 */
public class StudentsProxy implements Person{
    Student student;
    //被代理的学生对象
    public StudentsProxy(Person student){
        //只代理学生对象
        if(student.getClass() == Student.class){
            this.student = (Student)student;
        }
    }
    //代理上交班费,调用被代理学生的上交学费行为
    @Override
    public void giveMoney() {
        student.giveMoney();
    }
}

主类:

public class Main {

    public static void main(String[] args) {
        //被代理的学生Jet,他的学费由班长帮他上交
        Person jet = new Student("jet");
        //生成代理对象班长,把jet传给代理对象
        Person monitor = new StudentsProxy(jet);
        //实现被代理人的行为
        monitor.giveMoney();
    }
}

运行结果
运行结果
当然在代理类中可以加入更多的逻辑来完善学生类的任务功能,比如说输出什么时候交的学费。

 @Override
    public void giveMoney() {
        Date date = new Date();
        System.out.println(date.toString());
        student.giveMoney();
    }

运行结果:
运行结果
动态代理:
要是首先说动态代理的实现和概念,我想可能是个挺难理解的东西,所以我们先来看一个demo。
首先还是要先创建Person接口

/**
 * 创建Person接口
 * @author Jet
 */
public interface Person {
    void giveMoney();//上交学费
}

学生类实现Person接口

public class Student implements Person{
    private String name;
    public Student(String name){
        this.name = name;
    }
    @Override
    public void giveMoney() {
        try {
            Thread.sleep(1000);
            //假设上交学费时间花了1s
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "上交学费10000");
    }
}

时间类记录上交学费方法执行时间

public class MonitorUtil {
    private static ThreadLocal<Long> t1 = new ThreadLocal<>();
    /**
     * ThreadLocal是线程变量,是一个以ThreadLocal对象为键、任意对象为值得存储结构。这个结构被附带在线程上,
     * 也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值
     */
    public static void start(){
        t1.set(System.currentTimeMillis());
    }
    //结束时打印耗时
    public static void finish(String methodName){
        long finishTime =  System.currentTimeMillis();
        System.out.println(methodName+"方法耗时"+(finishTime - t1.get()) + "ms");
    }
}

创建StuInvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。

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

public class StuInvocationHandler<T> implements InvocationHandler {
    //invocationHandler持有的被代理对象
    T target;
    public StuInvocationHandler(T target){
        this.target = target;
    }

    /**
     * @param proxy 代表动态代理的对象
     * @param method 代表正在执行的方法
     * @param args  代表调用目标方法时传入的实参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" + method.getName() + "方法");
        MonitorUtil.start();//在代理过程中插入监测方法,计算方法耗时
        Object result = method.invoke(target,args);
        MonitorUtil.finish(method.getName());
        return null;
    }
}

创建动态代理对象:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
        //被代理的学生Jet,这个对象是被代理的对象
        Person jet = new Student("jet");
        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler studentHandler = new StuInvocationHandler<Person>(jet);
        //创建一个代理对象stuProxy来代理jet,代理对象的每个执行方法都会替换执行Invocation中invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class},studentHandler);
        //代理执行上交班费的方法
        stuProxy.giveMoney();
    }
}

最后将Proxy.newProxyInstance的源码附上:

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

那么动态代理是什么呢?
(动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员。 初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象。)
以上就是我对Java设计模式静态代理和动态代理的总结和理解,如果以后会有更深的学习还会补上。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值