关于动态代理实现的步骤及操作

关于动态代理实现的步骤及操作

知识重温背景:在Android APP插件化框架的实现中,需要HOOK AMS类的实例(该实例为单例实现)并做相关处理,需要使用到动态代理

一.静态代理


  • 静态代理较为简单:个人感觉和装饰模式类似,新建一个类,构造函数中传入一个被代理类的实例,在代理类中声明方法传入参数,并调用传入的被代理的实例中的方法,即实现了一个简单的静态代理。

缺点:1.JAVA中的代理是基于接口声明的,需要有一个接口声明被代理实例中要实现的方法,原因是代理类Proxy生成动态实例时是根据约定的接口实现的
2如果接口中增加一个方法,则所有的静态代理类中都要添加该方法
3.需要为每一个API都指定一个代理方法

实现代码如下
1.定义的接口类:
## IAction.java ##
public interface IAction {
    String fly(String flag);
    void run();
    void eat();
    void sleep();
}
2.生成具体实现类
## Pigeon.java ##
public class Pigeon implements IAction{

    @Override
    public String fly(String flag) {
        System.out.println("信鸽飞行..."+flag);
        return "成功";

    }

    @Override
    public void run() {
        System.out.println("信鸽跑路...");

    }

    @Override
    public void eat() {
        System.out.println("信鸽进食...");

    }

    @Override
    public void sleep() {
        System.out.println("信鸽休息...");

    }

}
3.静态代理类实现(简单的包装了一层,在调用被代理的Pigeon实例的方法之前,添加业务新需要的操作)
## PigeonStaticProxy.java ##
public class PigeonStaticProxy {
    private Pigeon pigeon;

    public PigeonStaticProxy(Pigeon pigeon) {
        this.pigeon = pigeon;
    }

    public void fly(String flag){
        System.out.println("绑上信件...");//【代理类】中添加的【被代理类】中没有的操作
        String result = pigeon.fly(flag);//【被代理类】中的fly() 方法
        System.out.println("信件已投递..."+result);//【代理类】中添加的【被代理类】中没有的操作
    }
}
4.Test
## Main.calss ##
public class Main {
    public static void main(String[] args) {
        Pigeon pigeon = new Pigeon();
        PigeonStaticProxy pigeonProxy = new PigeonStaticProxy(pigeon);
        pigeonProxy.fly("单程");// 静态代理实现
        // 动态代理实现
    }

}

二.动态代理

  • 简单的说动态代理是由系统代替手动生成类,是在使用的时候再生成一个代理类。进而调用实际被代理类的方法,JAVA中的动态代理需要使用到 Proxy类 和 InvocationHandler实现。
    具体实现和静态代理一样
    1.首先需要有统一的接口
    2.有一个具体实现类的实例
    3.实现InvocationHandler 该实现中添加需要在【被代理】对象操作之外额外的业务操作

    ## PigeonInvocationHandler.java ##
    public class PigeonInvocationHandler implements InvocationHandler {
    
        private IAction action;
    
        public PigeonInvocationHandler(IAction action) {
            this.action = action;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("动态代理:绑上信件");
            Object result = method.invoke(action, args);
            System.out.println("动态代理:信件已投送,返回结果:"+(result==null?"null":result.toString()));
            return result;
        }
    
        }
    

    4.Test-测试

    ## Main.java ##
     public class Main {
            public static void main(String[] args) {
                Pigeon pigeon = new Pigeon();
                // 动态代理实现
                PigeonInvocationHandler pigeonInvocationHandler = new PigeonInvocationHandler(pigeon);
                IAction actionDemoPro = (IAction) Proxy.newProxyInstance(pigeon.getClass().getClassLoader(), pigeon.getClass().getInterfaces(), pigeonInvocationHandler);
                actionDemoPro.fly("往返");
                actionDemoPro.run();//同时接口中的所有方法均可使用
                createProxyClassFile();//生成实际代理类的二进制代码 
            }
            //用来生成代理类类的class文件,可以反编译此.class文件,查看实际生成的代理类,其本质上是和上面静态代理类.java文件编译后生成的.class一样的,动态生成的代理类中间又经过了一层InvocationHandler执行业务定制的内容,TIP:如果ProxyGenerator该类不识别,可以remove掉默认的JRE:lib,然后重新Add
             public static void createProxyClassFile()   
              {   
                String name = "ProxySubject";   
                byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { IAction.class } );   
                try  
                {   
                  FileOutputStream out = new FileOutputStream( name + ".class" );   
                  out.write( data );   
                  out.close();   
                }   
                catch( Exception e )   
                {   
                  e.printStackTrace();   
                }   
            }   
     }
    

三动态代理内部实现

  • 1.Proxy的代码实现中,Proxy类的主要静态变量如下
    #

    // 映射表:用于维护类装载器对象到其对应的代理类缓存
    private static Map loaderToCache = new WeakHashMap();

    // 标记:用于标记一个动态代理类正在被创建中
    private static Object pendingGenerationMarker = new Object();

    // 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断
    private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());

    // 关联的调用处理器引用
    protected InvocationHandler h;

  • 2.Proxy的构造方法
    #

    // 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
    private Proxy() {} 
    
    // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
    protected Proxy(InvocationHandler h) {this.h = h;} 
    
  • 3.Proxy的静态方法
    #

    public static Object newProxyInstance(ClassLoader loader, Class

引用http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html 的总结

  • 动态代理实现经过以下四个步骤:
  • 1、实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
  • 2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类,(ps:因为此处是根据定义的Interface动态生成的实例,所以JAVA的动态代理,是基于设计的接口实现的,是其局限之一)
    Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  • 3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
    Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  • 4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
    Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
    为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
    生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值