代理模式和android插件化

代理模式

[TOC]

1 静态代理和动态代理

代理的概念:为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
白话文:简单的说,就是类似于买东西,厂商负责生产,货物交给商店来代理出售。客人跟商店来交互,但是其实买的是厂商的东西。

静态代理

package com.proxy.inter;

/**
 * 定义Demo接口
 */
public interface Demo {
    public void save();
}
package com.proxy.impl;

import com.proxy.inter.Demo;

/**
 * DemoImpl实现Demo接口并覆写save()方法
 * 真实主题,执行具体业务
 */
public class DemoImpl implements Demo {
    public void save() {
        System.out.println("调用save()方法");
    }
}
package com.proxy.impl;

import com.proxy.inter.Demo;
/**
 * DemoImplProxy 也实现了Demo接口,并覆写了save()方法,增加了自己的业务 
 * 代理主题,负责其他业务的处理
 */
public class DemoImplProxy implements Demo {
    Demo demoImpl = new DemoImpl();
    
    public void save() {
        System.out.println("开始记录日志");
        demoImpl.save();
        System.out.println("开始结束日志");
    }
}
package com.proxy.impl;

import com.proxy.inter.Demo;

/**
 * 开始记录日志
 * 调用save()方法
 * 开始结束日志
 */
public class Test {
    public static void main(String[] args) {
        Demo demoImplProxy = new DemoImplProxy();
        
        demoImplProxy.save();
    }
}

静态代理有一个缺点,每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类

所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持。

动态代理

java.lang.reflect.InvocationHandler接口的定义如下:

/**
*
*Object proxy:被代理的对象
*Method method:要调用的方法
*Object[] args:方法调用时所需要参数
*/
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

java.lang.reflect.Proxy类的定义如下:

/**
*CLassLoader loader:类的加载器
*Class<?> interfaces:得到全部的接口
*InvocationHandler h:得到InvocationHandler接口的子类的实例
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

具体实现

package com.proxy.inter;

/**
 * 定义DemoFirst接口
 */
public interface DemoFirst {
    public void saveFirst();
}
package com.proxy.impl;

import com.proxy.inter.DemoFirst;

/**
 * DemoFirstImpl实现DemoFirst接口,覆写saveFirst()方法
 * 真实主题,负责执行具体业务 
 */
public class DemoFirstImpl implements DemoFirst {

    @Override
    public void saveFirst() {
        System.out.println("调用saveFirst()方法");
    }

}
package com.proxy.impl;

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

/**
 * InvocationHandlerImple实现InvocationHandler接口,覆写invoke()方法
 * 代理主题的业务写在invoke()方法中
 */
public class InvocationHandlerImpl implements InvocationHandler {

    private Object target;
    
    public InvocationHandlerImpl(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("target : " + target.getClass().getName());
        System.out.println("proxy : " + proxy.getClass().getName());
        System.out.println("method : " + method.getName());
        System.out.println("args : " + args);
        System.out.println("开始记录日志");
        Object obj = method.invoke(target, args);
        System.out.println("结束记录日志");
        /*    
         * System.out.println("obj : " + obj.getClass().getName());
         * 本例中saveXXX方法没有返回值所以obj会报空指针异常
         */
        return obj;
    }
}
package com.proxy.impl;

import java.lang.reflect.Proxy;

import com.proxy.inter.DemoFirst;
/*import com.proxy.inter.DemoSecond;*/

public class Test {
    public static void main(String[] args) {
        DemoFirst first = new DemoFirstImpl();
        /*DemoSecond second = new DemoSecondImpl();*/

        //取得代理对象
        DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first
                .getClass().getClassLoader(), first.getClass().getInterfaces(),
                new InvocationHandlerImpl(first));
        //通过动态代理调用方法
        firstProxy.saveFirst();

        /*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second
                .getClass().getClassLoader(), second.getClass().getInterfaces(), 
                new InvocationHandlerImpl(second));
        secondProxy.saveSecond();*/
    }
}

优缺点

缺点:

  1. 如果是代理类,那么调用getclass等方法的时候,会无法得到预期的结果。

代理模式的应用

代理模式是非常好用的,在很多的地方都有着用途。比如spring的AOP,
代理模式有多种应用场合,如下所述:

  1. 远程代理,也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。比如说 WebService,当我们在应用程序的项目中加入一个 Web 引用,引用一个 WebService,此时会在项目中声称一个 WebReference 的文件夹和一些文件,这个就是起代理作用的,这样可以让那个客户端程序调用代理解决远程访问的问题;
  2. 虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。这样就可以达到性能的最优化,比如打开一个网页,这个网页里面包含了大量的文字和图片,但我们可以很快看到文字,但是图片却是一张一张地下载后才能看到,那些未打开的图片框,就是通过虚拟代里来替换了真实的图片,此时代理存储了真实图片的路径和尺寸;
  3. 安全代理,也可以是权限代理。用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候;
  4. 延迟加载,用代理模式实现延迟加载的一个经典应用就在 Hibernate 框架里面。当 Hibernate 加载实体 bean 时,并不会一次性将数据库所有的数据都装载。默认情况下,它会采取延迟加载的机制,以提高系统的性能。Hibernate 中的延迟加载主要分为属性的延迟加载和关联表的延时加载两类。实现原理是使用代理拦截原有的 getter 方法,在真正使用对象数据时才去数据库或者其他第三方组件加载实际的数据,从而提升系统性能。

推荐阅读更多精彩内容

  • 这部分主要是开源Java EE框架方面的内容,包括Hibernate、MyBatis、Spring、Spring ...
    杂货铺老板阅读 994评论 0 2
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李头阅读 2,728评论 2 10
  • 1.JVM 堆内存和非堆内存 堆和非堆内存按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据...
    yanzhu728阅读 458评论 0 0
  • 一、概述   代理模式我们接触的就比较多了,所谓的代理模式就是,给某一个对象提供一个代理对象,并由代理对象控制对原...
    骑着乌龟去看海阅读 616评论 0 9
  • 代理模式 1 静态代理和动态代理 代理的概念:为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共...
    遥遥的远方阅读 148评论 0 1
  • 酒的风格是出色、香、味三大要素组成、按酒香的类别来划分乃情理之中、而我们日常生活中谈到酒的香型、均酒白酒...
    望月书斋阅读 121评论 0 2
  • 阿萌萌200天学习笔记Day101 这一切工具都是为了让你更真诚地沟通,而不是用工具替代了真诚。 《高效演讲》[美...
    阿萌萌Summeng阅读 128评论 0 1
  • 摘要:给大家分享一下我在建站公司常用的插件 博客地址:Small Lucky 1.OwlCarousel | 2....
    God_Lee阅读 219评论 0 1
  • 近来几日,心情颇有些烦躁。也许与北京每日的炙热脱不了干系吧,但也与自己无法沉静的心有关。 来京半月余,每日与儿...
    我叫张能能阅读 176评论 1 1