当晚

导航

【Java】代理模式、反射机制-动态代理

关于代理模式和动态代理参考自:https://www.cnblogs.com/gonjan-blog/p/6685611.html

这里通过参考博客中的例子整理个人理解。

代理模式:

访问某个类的方法由直接调用方法,变为通过中间人练习。

即调用方➡功能提供者,变更为调用方➡代理人➡功能提供者。

这样做的好处:

1.调用方不再关注功能提供者的具体行为,专为代理人统一关注,调用方只用关注代理人的行为(接口)。

2.代理人可以在真正调用功能提供者的方法前后进行再加工提供部分行为。

静态代理:

在编译阶段已经知道代理人、功能提供者、调用方的关系。

动态代理:

代理人在编译阶段不知道调用方和功能提供者的类型,在运行时通过传入的参数动态建立代理关系。

因此动态代理的加工行为可以对拥有被代理人临时生效,比如计算任何功能提供者执行方法的时间。。

以下是例子:

静态代理:

Person接口代表所有学生,所有学生都有交班费的行为

package com.xdsux.java.proxy;

public interface Person {
    //静态代理与功能提供者的统一接口
    void giveMoney();
}

Student实现了Person接口的交班费行为:

package com.xdsux.java.proxy;

public class Student implements Person {

    @Override
    public void giveMoney() {
        System.out.println("学生提交班费:50");

    }

}

Monitor即代理(班长),班长可以找任何学生提交班费:

package com.xdsux.java.proxy;

public class Monitor implements Person {
    //班长即代理,持有学生实例
    Student stu;
    
    public Monitor(Person stu) {
        this.stu = (Student)stu;
    }

    @Override
    public void giveMoney() {
        //班长叫学生交班费
        stu.giveMoney();
    }

}

测试,也就是老师叫班长去收班费:

package com.xdsux.java.proxy;

public class TestProxy {
    public static void main(String[] args) {
        //某学生
        Student stu = new Student();
        //某班长
        Monitor mon = new Monitor(stu);
        mon.giveMoney();
    }
}

1.班长可以向任何一个学生收班费,在收取班费时可以加入其他动作,比如查询学生上次是否未交。

2.班长可以采用单例模式(一个班只有一个班长)

3.学生的缴费行为可以变动(学生出现子类贫困生,可能不需要交班费),但老师不必关心,班长负责和学生重新确定缴费行为,老师可以依然调用mon.giveMoney

 

动态代理

代理类需要实现InvovationHabdler接口:

 

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

public class StuInvocationHandler<T> implements InvocationHandler {

    // 事先不知道代理谁
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    /**
     * proxy:代理动态对象 method:代表需要执行的方法 args:调用目标方法时要传入的参数
     */
    @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 result;
    }

}

代理会根据传入的实例和参数执行方法,并在每次代理时,计算目标方法的执行时间:

package com.xdsux.java.proxy;

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

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

 

posted on 2018-08-23 16:19  当晚  阅读(772)  评论(0编辑  收藏  举报