非官方解读代理模式

代理模式(Proxy) : 代理模式就是多一个代理类出来,替原对象进行一些操作.对方法进行加强.而代理类充当一个中介的角色.我们不直接调用原方法.而是通过代理类进行调用,中间可进行自定义处理.Spring Aop中的通知就是由此而来.代理分为静态代理,动态代理(Jdk代理),cglib代理三种,下文将进行阐述.

作者是个二吊子,如果描述有误请指出.


使用场景

我们突然接到一个需求,需要对某些具有特殊身份的数据进行验证,验证其合法性.这个时候传统操作是直接改动原有代码,增加相应处理逻辑.于是乎我们一顿操作发现有三个地方需要验证.于是脸滚键盘对着三个地方进行代码改动.一顿输出后,需求解决,测试,上线,完美闭环.但是第二天我们又接到需求,需要对普通身份的数据也进行验证.这个时候我们就发现,我们又要操作三个地方.可真是新三年,旧三年,缝缝补补又三年.长此以往我们代码的可读性越来越差,维护起来要命.于是引出了代理模式.

静态代理

uml图
静态代理uml

抽象接口: ITeacherDao, 实现类: TeacherDao, 代理类: TeacherDaoProxy ,客户端 : Client

/**
 * @Description: 接口类
 * @Author: gaofan
 * @Date: 2020/3/24 12:02
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public interface ITeacherDao {

    public void teach();
}

/**
 * @Description: 被代理类
 * @Author: gaofan
 * @Date: 2020/3/24 12:03
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class TeacherDao implements  ITeacherDao {
    @Override
    public void teach() {
        System.out.println("王老师正在讲课");
    }
}
/**
 * @Description: 代理类
 * @Author: gaofan
 * @Date: 2020/3/24 12:03
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class TeacherDaoProxy implements ITeacherDao{

    private TeacherDao teacherDao;

    @Override
    public void teach() {
        System.out.println("打开课件");
        teacherDao.teach();
        System.out.println("关闭课件");
    }

    public TeacherDaoProxy(TeacherDao teacherDao) {
        this.teacherDao = teacherDao;
    }
}
/**
 * @Description: TODO
 * @Author: gaofan
 * @Date: 2020/3/24 12:05
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class Client {


    public static void main(String [] args){
        TeacherDaoProxy proxy = new TeacherDaoProxy(new TeacherDao());
        proxy.teach();
    }
}

类型: 静态代理
原理: 实现类与代理类均实现抽象类接口,对其方法进行实现.代理类中聚合被代理类,其实现方法中通过聚合代理类调用目标方法.可以在代理类方法中加上我们需要增强的功能与处理.
缺点: 代理类需要实现接口,代码编译时已经确定了.

动态代理

通过jdk实现,核心是InvocationHandler , Proxy.newProxyInstance().代理类实现InvocationHandler invoke()方法,我们的增强方法也在这个方法中.通过Proxy.newProxyInstance()产生代理实例进行调用.
uml图
动态代理uml

动态代理与静态代理的差别: 我们在代理类中并没有去实现接口,而是通过聚合的方式来实现.动态扩展,让类与类之间耦合度降低

/**
 * @Description: 接口类
 * @Author: gaofan
 * @Date: 2020/3/24 12:02
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public interface ITeacherDao {

    void teach();

    void say();
}

/**
 * @Description: 具体实现
 * @Author: gaofan
 * @Date: 2020/3/24 12:03
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {
        System.out.println("王老师正在讲课");
    }

    @Override
    public void say() {
        System.out.println("王老师开始吹牛了");
    }
}

/**
 * @Description: 代理类
 * @Author: gaofan
 * @Date: 2020/3/24 12:15
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class ProxyFactory implements InvocationHandler {

    private Object object;

    public ProxyFactory(Object object) {
        this.object = object;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass()
                .getInterfaces(),this);
//        return object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(!method.getName().equals("say")){
            System.out.println("打开书本");
        }
        Object obj = method.invoke(object, args);
        if(!method.getName().equals("say")){
            System.out.println("关闭书本");
        }
        return obj;
    }
}
/**
 * @Description: TODO
 * @Author: gaofan
 * @Date: 2020/3/24 12:17
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class Client {

    public static void main(String [] args){
        ProxyFactory factory = new ProxyFactory(new TeacherDao());
        ITeacherDao proxyInstance = (ITeacherDao)factory.getProxyInstance();
        proxyInstance.say();

        proxyInstance.teach();
    }
}

类型: 动态代理
原理: 通过Proxy.newProxyInstance()产生实例,自定义实现InvocationHandler的invoke()方法进行增强.
缺点: 依赖接口实现,必须要有接口类

cglib代理

通过非jdk自带jar实现,能够对类进行加强,并不仅限于接口
uml图
cglib uml

动态代理依赖接口实现,而cglib则是直接对类下手了,内部实现应该是字节码.留着后边探索了

/**
 * @Description: 被代理类
 * @Author: gaofan
 * @Date: 2020/3/24 12:47
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class TeacherDao {

    public void teach() {
        System.out.println("王老师正在讲课");
    }

    public void say() {
        System.out.println("王老师开始吹牛了");
    }
}


/**
 * @Description: 代理类
 * @Author: gaofan
 * @Date: 2020/3/24 12:48
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class ProxyFactory implements MethodInterceptor {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance(){
        // 创建工具类
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(target.getClass());
        // 设置回调函数
        enhancer.setCallback(this);
        // 创建子类对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("cglib 代理开始了");
        Object obj = method.invoke(target, objects);
        System.out.println("cglib 代理结束了");
        return obj;
    }
}
/**
 * @Description: TODO
 * @Author: gaofan
 * @Date: 2020/3/24 12:48
 * @Copyright: 2020 www.withu.top Inc. All rights reserved.
 **/
public class Client {

    public static void main(String[] args) {
        TeacherDao teacherDao = new TeacherDao();
        ProxyFactory factory = new ProxyFactory(teacherDao);
        TeacherDao dao = (TeacherDao) factory.getProxyInstance();
        dao.teach();

        dao.say();
    }
}

原理: 代理类实现MethodInterceptor ,实现其intercept 方法(拦截器),通过Enhancer 工具类设置父类,设置回调,创建子类对象并返回实例.客户端通过返回实例进行调用.
优点: 直接对类增强.对接口没有依赖


本文借鉴尚硅谷Java设计模式,韩顺平图解java,传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值