美文网首页
java代理模式与动态代理的实现

java代理模式与动态代理的实现

作者: 小风风吖 | 来源:发表于2018-12-05 17:16 被阅读0次

1.什么是代理模式

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。本文将详细介绍代理模式与动态代理的实现方式。


百度图-侵删.jpg

组成:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
(以上摘自百度百科)

2.为什么使用代理模式

1.真实角色的职责清晰。
2.对真实角色的访问保护。
3.高扩展性。
比如:在数据库的操作业务中,数据库对象就是真实角色,只负责增删改查。beginTransaction 和commit不属于它的职责,但实际业务总是需要调用怎么办?可以创建一个代理,持有数据库的真实访问,外部总是通过代理来操作数据。请看下面的栗子↓

3.一颗栗子

就拿数据库举个栗子吧,首先根据基本组成,定义接口和真实类、代理类。

数据库接口-增删改查

interface IDao {
        void add(Object o);
        
        void delete(Object o);
        
        void update(int id, Object o);

        Object find(int id);
    }

真实类 实现(此处用一个map模拟实际数据操作)

class SimpleDao implements IDao {
        private List<Object> mDataBase = new ArrayList<>();

        @Override
        public void add(Object o) {
            mDataBase.add(o);
        }

        @Override
        public void delete(Object o) {
            mDataBase.remove(o);
        }

        @Override
        public void update(int id, Object o) {
            mDataBase.remove(id);
            mDataBase.add(id, o);
        }

        @Override
        public Object find(int id) {
            return mDataBase.get(id);
        }
    }

代理类 实现

class DaoProxy implements IDao {
        private IDao mDao;

        public DaoProxy(IDao dao) {
            this.mDao = dao;
        }

        private void beginTransaction() {
            System.out.println("读写开始前,开启数据库!");
        }

        private void commit() {
            System.out.println("读写结束,关闭数据库!");
        }

        @Override
        public void add(Object o) {
            beginTransaction();
            mDao.add(o);
            commit();
        }
        ......  //废话就别看了下面都一样
    }

实际使用时

SimpleDao simpleDao = new SimpleDao();
DaoProxy proxy = new DaoProxy(simpleDao);
proxy.add(new Object());
......

这就是简单的静态代理实现啦,这样看貌似成了装饰器模式?别急,我们先来分析一下两种模式的定义:
装饰器模式:侧重对于目标类中核心逻辑的扩展,依然是以目标类为中心。
代理模式:更加侧重于对目标类的访问限制与处理,某些场景甚至不需要调用目标类的实现,比如👇

        @Override
        public void add(Object o) {
            if(amIHappy()) {
                beginTransaction();
                mDao.add(o);
                commit();
            } else {
                System.out.println("不高兴,我不干!");
            }
        }

        private boolean amIHappy() {
            ......
        }

上面就是代理模式的静态代理基本实现方式了,然后我们接着来看看java的动态代理。

动态代理

1.动态代理简介

首先,相对于静态代理,动态代理中的代理类不需要实现与目标类相同的接口,而且不依赖于接口的具体实现,理论上可以代理所有的类所有方法。但因为要考虑到涉及到的业务,所以要求面向接口代理。

实现机制:运行时创建一个虚拟的代理类,在代理的目标方法实际执行时,通过java的反射技术获取到该方法对象,并在执行前或执行后添加需要的操作,这需要实现一个InvocationHandler接口,来看一个具体的实现

2.又是一颗栗子

class DaoProxy {

        这里需要注意,返回值只能是一个接口,而不能是具体的是实现类
        public IDao createProxy(IDao target) {
            此方法生成的虚拟类是根据目标的Class文件拿到的父类接口生成,因此不能强转成实现类
            return (IDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            beginTransaction();
                            Object invoke = method.invoke(target, args);
                            commit();
                            return invoke;
                        }
                    });
        }

        private void beginTransaction() {
            System.out.println("读写开始前,开启数据库!");
        }

        private void commit() {
            System.out.println("读写结束,关闭数据库!");
        }
    }

如上,实际返回的是一个匿名内部代理类,类型为$Proxy1(数字可能是其它),可以强转成目标类的父类接口使用,等于是生成了一个全是空方法的接口实现类。然后再实际执行到某个方法的时候,会执行 invoke 方法中的逻辑,这里我们调用了目标类的具体实现。
具体使用:

SimpleDao simpleDao = new SimpleDao();
IDao proxy = new DaoProxy().createProxy(simpleDao);
proxy.add(new Object());
......

//------------我是手动分割线------------

3.无需实现的接口代理

接下来,我们要将一个比较极端的代理方式,可以完全抛开具体实现,进行接口的完全代理。这种代理方式中我们只关心方法传入的参数和方法本身,重点逻辑全在代理中实现,完全无需接口的具体实现。👇

class LogProxy {

        public <T> T createProxy(Class<T> targetInterface) {
            return (T) Proxy.newProxyInstance(targetInterface.getClassLoader(), new Class[]{ targetInterface },
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.print("开始输出日志------->");
                            System.out.print("调用方法:" + method.getName() + makeArgsText(args));
                            System.out.print("<-------日志输出结束");
                            System.out.println();
                            return null;
                        }
                    });
        }

        private String makeArgsText(Object[] args) {
            StringBuilder builder = new StringBuilder();
            builder.append(",   共有").append(args.length).append("个参数:  ");
            for(Object item : args) {
                builder.append(item.toString()).append(" & ");
            }
            return builder.toString();
        }
    }

使用此代理并开始执行:

IDao proxy = new LogProxy().createProxy(IDao.class);
proxy.add("item");
proxy.update(0, "newItem");

得到的结果是:

开始输出日志------->调用方法:add,   共有1个参数:  “item”,<-------日志输出结束
开始输出日志------->调用方法:update,   共有2个参数:  “0”,“newItem”,<-------日志输出结束

这种代理方式使用到的场景,都是完全不关心接口的实现逻辑,代理类中已经完全集成了需要的操作,只需要取到接口方法上定义的注解和实际调用时传入的参数,用这些数据进行实际的操作。
安卓开发中使用的Retrofit框架就是通过这种方式实现的动态代理,日后有时间会再更一篇文章来深入的扒一扒Retrofit框架的实现原理。

以上就是本文的全部内容,如有不足请多指教,共同进步。

转载请注明出处,@via 小风风吖-java代理模式与动态代理的实现 蟹蟹。

相关文章

  • 代理

    来源:java动态代理实现与原理详细分析 代理模式是常用的java设计模式,他的特征是代理类与委托类实现同样的接口...

  • java 动态代理

    1、代理模式 2、java 动态代理2.1 InvocationHandler 实现类告诉程序运行动态生成的代理...

  • Java实现动态代理

    参考文章:代理模式及Java实现动态代理 代码: 运行截图:

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • 代理模式

    JAVA的动态代理模式:A接口,A1子类实现A接口,A2子类实现A接口。那么JAVA的动态代理模式会A1、A2.....

  • Proxy - 代理模式

    注意:全文是基于Java来描述和实现的!代理模式的实现有很多种方法:静态代理,动态代理(又分为反射实现的动态代理,...

  • 设计模式之代理

    设计模式之代理模式 一、定义 在Java中代理的实现一般分为三种:JDK静态代理、JDK动态代理以及CGLIB动态...

  • 代理模式

    代理模式分静态代理与动态代理,而动态代理又在Spring中与两个实现:1.基于JDK的动态代理(通过接口实现)2....

  • 设计模式

    结构型模式 介绍一下 如何实现动态代理? 考察点:动态代理流程参考回答: Java实现动态代理的大致步骤如下: 1...

  • Spring AOP详解

    AOP AOP的实现一般都是基于 代理模式 ,在JAVA中采用JDK动态代理模式,但是我们都知道,JDK动态代理模...

网友评论

      本文标题:java代理模式与动态代理的实现

      本文链接:https://www.haomeiwen.com/subject/zplicqtx.html