zoukankan      html  css  js  c++  java
  • Java动态代理

    Java动态代理简介

    1.1 动态代理的特点

      字节码随用随创建,随用随加载。 

      它与静态代理的区别也在于此。

      因为静态代理是字节码一上来就创建好,并完成加载。

        装饰者模式就是静态代理的一种体现。

    1.2 动态代理常用的有两种方式  

      1.基于接口的动态代理

        提供者:JDK官方的Proxy类

        要求:被代理类至少实现一个接口

      2.基于子类的动态代理

        提供者:第三方的CGLib ,如果报 asmxxx的异常,需要导入asm.jar

        要求:被代理类不能是被final修饰的类(即最终类)

    需求:

       假设一个盖房子的工程(bulid a house)需要找工人到工地干活,要求工人会搬砖(move brick),砌墙(build a wall)。

    一个包工头承接了这项工程,由包工头去找工人干活。此时的包工头即是代理的角色(proxyBulidAHouse)。

      使用动态代理对方法进行增强。

    2  基于接口的动态代理—Proxy类

    2.1新建盖房子的接口(IBulidHouse)

    /**
    * 建房子的要求
    * 1.搬砖 moveBrick
    * 2.砌墙 bulidWall
    * 需要给工人工钱
    * 工钱 money
    *
    */
    public interface IBuildHouse {
    /**
    * 搬砖的方法
    * @param money 搬砖的工钱
    */
    public void moveBrick(Float money);

    /**
    * 砌墙的方法
    * @param money 砌墙的工钱
    */
    public void buildWall(Float money);
    }

    2.2 接口实现类


    /**
    * 一个工人
    * 实现接口表示这个工人符合会搬砖和会砌墙的要求
    */
    public class BuildHouseImpl implements IBuildHouse{

    public void moveBrick(Float money) {
    System.out.println("今天搬砖得了"+money+"元");
    }

    public void buildWall(Float money) {
    System.out.println("今天砌墙得了"+money+"元");
    }
    }

    2.3代理类对象,对被代理对象的方法进行增强

    public class ProxyBuildHouse {

        public static void main(String[] args) {

    final IBuildHouse buildHouse = new BuildHouseImpl(); //直接new 一个被代理对象

    /**
    * 代理:
    * 间接。
    * 获取代理对象:
    * 要求:
    * 被代理类最少实现一个接口
    * 创建的方式
    * Proxy.newProxyInstance(三个参数)
    * 参数含义:
    * ClassLoader:和被代理对象使用相同的类加载器。
    * Interfaces:和被代理对象具有相同的行为。实现相同的接口。
    * InvocationHandler:
    * 如何代理。
    * 策略模式:使用场景是:
    * 数据有了,目的明确。
    * 如何达成目标,就是策略。
    */

    IBuildHouse proxyBuildHouse = (IBuildHouse) Proxy.newProxyInstance(
    buildHouse.getClass().getClassLoader(),
    buildHouse.getClass().getInterfaces(),
    new InvocationHandler() {

    /**
    * 执行被代理对象的任何方法,都会经过该方法。
    * 此方法有拦截的功能。
    *
    * 参数:
    * proxy:代理对象的引用。不一定每次都用得到
    * method:当前执行的方法对象
    * args:执行方法所需的参数
    *返回值:
    * 当前执行方法的返回值
    */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    String name = method.getName();
    Float money = (Float) args[0];

    Object reValue = null;

    if("moveBrick".equals(name)){
    /**
    * 对砌墙方法进行增强,如果工钱大于500
    * 包工头收百分二十工钱,工人实际到手工钱的百分之八十
    */
    if(money>500){
    reValue=method.invoke(buildHouse,money*0.8f);
    }
    }

    if("buildWall".equals(name)){
    /**
    * 对砌墙方法进行增强,如果工钱大于500
    * 包工头收百分二十工钱,工人实际到手工钱的百分之八十
    */
    if(money>500){
    reValue=method.invoke(new BuildHouseImpl(),money*0.8f);
    }
    }
    return reValue;
    }
    }
    );

    //直接调用搬砖和砌墙方法
    //buildHouse.moveBrick(700f);
    //buildHouse.buildWall(600f);


    //代理对象执行搬砖和砌墙的方法
    proxyBuildHouse.moveBrick(600f);
    proxyBuildHouse.buildWall(700f);

    }
    }

    3  基于子类的动态代理—CGLib.Enhaner类

    3.1 新建BuildHouseImpl类(没有实现接口)

    /**
    * 一个工人
    * 没有实现接口
    */
    public class BuildHouseImpl {

    public void moveBrick(Float money) {
    System.out.println("今天搬砖得了"+money+"元");
    }

    public void buildWall(Float money) {
    System.out.println("今天砌墙得了"+money+"元");
    }
    }

    3.2 新建CglibBuildHouse代理类(没有实现接口)

    public class CglibBuildHouse {
    public static void main(String[] args) {

    final BuildHouseImpl buildHouse = new BuildHouseImpl();

    /**
    * 动态代理:
    * 特点:字节码随用随创建,随用随加载
    * 作用:不修改源码的接触上对源码进行增强
    * 分类:基于接口的动态代理
    * 基于子类的动态代理
    *基于子类的动态代理:
    * 涉及的类:Enhancer
    * 提供者:第三方cglib库
    * 如何创建代理对象:
    * 使用Enhancer类的create方法
    * 创建代理对象的要求:
    * 被代理类不能是最终类
    * create方法的参数:
    * Class:字节码
    * 作用:用于指定被代理对象的字节码
    *
    * Callback:用于提供增强的代码
    * 它是让我们写如何代理,一般写一个该接口的实现类,通常情况下写一个匿名内部类,但不是必须的。
    * 此接口的实现类都是谁用谁写
    * 一般写该接口的子类的实现类:MethodInterceptor
    *
    */
    BuildHouseImpl cgLibBuildHouse = (BuildHouseImpl) Enhancer.create(buildHouse.getClass(), new MethodInterceptor() {
    /**
    * 执行被代理对象的任何方法都会经过该方法
    * @param proxy
    * @param method
    * @param objects
    * 以上三个参数和基于接口动态代理中invoke方法的参数是一样的
    * @param methodProxy 当前执行方法的代理对象
    * @return
    * @throws Throwable
    */
    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    //获取被代理类方法名
    String name=method.getName();
    //获取方法所需参数
    Float money = (Float) objects[0];
    Object returnValue = null;

    if("moveBrick".equals(name)){
    /**
    * 对砌墙方法进行增强,如果工钱大于500
    * 包工头收百分二十工钱,工人实际到手工钱的百分之八十
    */
    if(money>500){
    returnValue=method.invoke(buildHouse,money*0.8f);
    }
    }
    if("buildWall".equals(name)){
    /**
    * 对砌墙方法进行增强,如果工钱大于500
    * 包工头收百分二十工钱,工人实际到手工钱的百分之八十
    */
    if(money>500){
    returnValue=method.invoke(buildHouse,money*0.8f);
    }
    }

    return returnValue;
    }
    });

    cgLibBuildHouse.buildWall(600f);
    cgLibBuildHouse.moveBrick(600f);
    }
    }
  • 相关阅读:
    UE4 径向模糊radiu blur
    UE4 小笔记
    UE4 Fade out Mesh
    测试一下运行代码
    javascript——限制范围的拖拽
    javascript——拖拽函数封装
    一个等高布局的小实例
    javascript——拖拽原理小实例
    javascript——自定义右键菜单
    javascript——事件默认行为
  • 原文地址:https://www.cnblogs.com/lifengSkt/p/12907451.html
Copyright © 2011-2022 走看看