代理模式

代理模式是一个非常常见的模式,他有非常多的变种。

比如说远程代理,他可以让操作远程对象像操作本地对象一样的容易

还有虚拟代理,他主要是代理一些加载特别缓慢的对象,先展示给用户的是一个代理对象,然后异步加载真正的对象,来提高系统的响应速度

代理模式的变种是在是太多了,今天我主要给大家介绍的是保护代理,我分别用静态代理和动态代理两种方式去实现保护代理

我们都知道,对于系统的升级最好要对原先的代码零入侵,也就是说不修改原来的代码,代理模式就做到了这一点。

我们先来看看以下场景:假如有一个Person类,我们实现了他的get/set方法,但是呢,有一些时候,我们需要为这些接口设置一些权限,不是每个人都能去修改访问的,这种情况下,我们就可以用到保护代理来进行权限控制了。

我们假设有三个属性,姓名,年龄,成绩,看自己没有修改成绩的权限,看别人没有所有修改的权限

我们先看看静态代理是如何实现的:

这里写图片描述
我们实现了一个自己的代理,一个别人的代理,来看看代码

public interface Person {
    String getName();
    void setName(String name) throws IllegalAccessException;
    int getAge();
    void setAge(int age) throws IllegalAccessException;
    float getGrade();
    void setGrade(float grade) throws IllegalAccessException;
}


public class PersonImp implements Person {
    private String name;
    private int age;
    private float grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public float getGrade() {
        return grade;
    }
    public void setGrade(float grade) {
        this.grade = grade;
    }
}


public class OwnerProxy implements Person{
    Person person;
    public OwnerProxy(Person person) {
        this.person = person;
    }
    @Override
    public String getName() {
        return person.getName();
    }

    @Override
    public void setName(String name) throws IllegalAccessException {
        person.setName(name);
    }
    @Override
    public int getAge() {
        return person.getAge();
    }
    @Override
    public void setAge(int age) throws IllegalAccessException {
        person.setAge(age);
    }
    @Override
    public float getGrade() {
        return person.getGrade();
    }
    @Override
    public void setGrade(float grade) throws IllegalAccessException {
        throw new IllegalAccessException("没有修改权限");
    }
}


public class NonOwnerProxy implements Person{
    Person person;
    public NonOwnerProxy(Person person) {
        this.person = person;
    }
    @Override
    public String getName() {
        return person.getName();
    }
    @Override
    public void setName(String name) throws IllegalAccessException {
        throw new IllegalAccessException("没有修改权限");
    }
    @Override
    public int getAge() {
        return person.getAge();
    }
    @Override
    public void setAge(int age) throws IllegalAccessException {
        throw new IllegalAccessException("没有修改权限");
    }
    @Override
    public float getGrade() {
        return person.getAge();
    }
    @Override
    public void setGrade(float grade) throws IllegalAccessException {
        throw new IllegalAccessException("没有修改权限");
    }
}

写一个测试方法

 public static void main(String[] args) throws IllegalAccessException {
        Person person=new PersonImp();
        person.setName("张三");
        person.setAge(18);
        person.setGrade(99);

        Person ownerProxy=new OwnerProxy(person);
        System.out.println(ownerProxy.getGrade());
        //ownerProxy.setGrade(11);

        Person nonOwnerProxy=new NonOwnerProxy(person);
        nonOwnerProxy.setAge(11);
    }
    运行结果:
    99.0
Exception in thread "main" java.lang.IllegalAccessException: 没有修改权限
    at proxypattern.staticproxy.NonOwnerProxy.setAge(NonOwnerProxy.java:33)
    at proxypattern.staticproxy.Main.main(Main.java:21)

其实静态代理所做的事情非常简单,就是拿到要代理的对象,然后把他封装进代理类中,然后重写其所有方法,有权限的就委托给被代理对象,没权限就抛出异常。

我们来看看动态代理是怎么做的(JDK的动态代理)

这里写图片描述

其实动态代理是在运行时生成一个代理类,而静态代理的代理类是实现编译好的,因此动态代理更具有弹性。

我们来看看代码,Person 和 PersonImp几乎和静态代理的一样,我就不赘述了

public class NonOwnerHandler implements InvocationHandler{
    Person person;
    //注入被代理对象
    public NonOwnerHandler(Person person) {
        this.person = person;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过反射,得到方法名称,看看是否有操作权限,没有就抛出异常,有就通过反射调用
        if (method.getName().startsWith("set"))
            throw new IllegalAccessException("没有修改权限");
        else
            return method.invoke(person,args);
    }
}


public class OwnerHandler implements InvocationHandler{
    Person person;
    public OwnerHandler(Person person) {
        this.person = person;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("setGrade"))
            throw new IllegalAccessException("没有修改权限");
        else
            return method.invoke(person,args);
    }
}

//用简答工厂封装一下,方便使用
public class NonOwnerProxyFactory {
    public static Person getNonOwnerProxy(Person person){
    //返回代理对象(实质是通过字节码的重组生成新的类)
        return (Person) Proxy.newProxyInstance(person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
                new NonOwnerHandler(person));
    }
}


public class OwnerProxyFactory {
    public static Person getNonOwnerProxy(Person person){
        return (Person) Proxy.newProxyInstance(person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
                new OwnerHandler(person));
    }
}

写个测试类

public static void main(String[] args) {
        Person person=new PersonImp();
        person.setName("张三");
        person.setAge(18);
        person.setGrade(99);

        Person nonOwner=NonOwnerProxyFactory.getNonOwnerProxy(person);
        System.out.println(nonOwner.getAge());
        nonOwner.setAge(1);
运行结果:
18
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
    at com.sun.proxy.$Proxy0.setAge(Unknown Source)
    at proxypattern.dynamicproxy.Main.main(Main.java:18)
Caused by: java.lang.IllegalAccessException: 没有修改权限
    at proxypattern.dynamicproxy.NonOwnerHandler.invoke(NonOwnerHandler.java:22)
    ... 2 more

cglib的动态代理和JDK的原理都是一样的,都是运行时通过字节码的重组生成新的类,但是cglib是通过继承被代理对象的类生成新的代理类,而JDK则是通过与被代理对象实现相同的接口实现代理类。

代理模式的用途非常的广泛,总的来说就是控制访问,然后基于你的访问来制订访问策略。

PS:源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值