1. 程式人生 > >Java動態代理模式 -- 保護代理

Java動態代理模式 -- 保護代理

dna 接口 private 意義 except handle loader param lac

意義

將接口的調用統一到一個函數裏處理,然後再去具體實例調用相應的方法,充當一個分發器的作用

user -> handler -> method

字典

動態:指的是在程序運行時才創建代理類

代理:與被代理類具有相同的屬性,也就是被代理類有run方法,它也有run方法

保護代理:限制接口類的某些方法給特定的對象使用

Proxy類:Java反射包自帶,其中newProxyInstance可以返回接口實現類的實例

組成

1.接口

Person類:其中有name與score相關的方法

自己本人可以修改名字但不能修改分數

別人可以修改分數不能修改名字

public interface PersonBean {
    String getName();
    
void setName(String name); int getScore(); void setScore(int score); }

2.實現接口的類

public class PersonBeanImpl implements PersonBean {
    private String name;
    private int score;

    public PersonBeanImpl (){
    }

    public PersonBeanImpl (String name,int score){
        this.name = name;
        
this.score = score; } public String getName (){ return name; } public void setName (String name){ this.name = name; } public int getScore (){ return score; } public void setScore (int score){ this.score = score; } }

3.實現InvocationHandler的handler類

  它的invoke方法利用反射,PersonBean的方法調用時會來調用invoke,因此可以在invoke方法體實現相應邏輯,

  實例中就是限定某些方法允許調用,某些方法會拋出異常

  3.1 自身handler:當創建這個handler實例時,就說明只能修改name不能修改score

public class OwnInvocationHandler implements InvocationHandler {
    // 需要代理的對象
    private PersonBean personBean;

    OwnInvocationHandler (PersonBean personBean){
        this.personBean = personBean;
    }

    // 代理設置規則
    public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
        String methodName = method.getName();
        // 自己不能設置自己的分數
        if ("setScore".equals(methodName)) {
            throw new IllegalAccessException("自己不能給自己打分");
        } else {
            return method.invoke(personBean, args);
        }
    }
}

  3.2 他人handler:當創建這個handler實例時,就說明只能修改score不能修改name

public class OtherInvocationHandler implements InvocationHandler {
    // 需要代理的對象
    private PersonBean personBean;

    OtherInvocationHandler (PersonBean personBean){
        this.personBean = personBean;
    }

    // 代理設置規則
    public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
        String methodName = method.getName();
        // 不能修改別人的名字
        if ("setName".equals(methodName)) {
            throw new IllegalAccessException("不能修改別人的名字");
        } else {
            return method.invoke(personBean, args);
        }
    }
}

4.生產handler類的工廠

通過Proxy的newProxyInstance獲取PersonBean對象

它的主要作用:將傳入的personBean與指定的InvocationHandler綁定,當PersonBean調用方法時,會去InvocationHandler調用invoke方法

public class ProxyFactory {
    /**
     * 獲得 個人 代理
     * @param personBean
     * @return
     */
    public PersonBean getOwnerProxy(PersonBean personBean) {
        return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new OwnInvocationHandler(personBean));
    }

    /**
     * 獲得 其他人 代理
     * @param personBean
     * @return
     */
    public PersonBean getOtherProxy(PersonBean personBean) {
        return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new OtherInvocationHandler(personBean));
    }
}

參考《Head First 設計模式》 -- P474

Java動態代理模式 -- 保護代理