精华内容
下载资源
问答
  • Java局域网通信——飞鸽传书源代码 28个目标文件 内容索引:JAVA源码,媒体网络,飞鸽传书 Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java...
  • 动态代理代码实现

    2017-07-09 16:32:18
    java 常用的两种动态代理代码实现:jdk动态代理、CGLIB动态代理
  • JAVA JDK静态代理动态代理、CGlib代理代码演示 为对象增加功能
  • 使用java完成动态代理的演示代码,适合初学者理解动态代理的功能,进行参考,本代码是简单的demo代码,仅用于学习参考。
  • 清楚的讲解了Java动态代理机制代码原理,希望能够帮助大家理解!
  • 四、动态代理的JDK实现原理 4.1核心类/接口 4.2 代理类$Proxy0解析 4.3 动态代理的经典使用五、手写代码模拟JDK动态代理六、参考资料项目源码已经上传,欢迎点击下载~先将自己总结的Java动态代理UML图放在前面,...

    前言

    文章目录如下,便于快速索引

    一、什么叫代理?

    二、什么叫动态代理?

    三、动态代理有什么优势?

    四、动态代理的JDK实现原理

        4.1核心类/接口

        4.2 代理类$Proxy0解析

        4.3 动态代理的经典使用

    五、手写代码模拟JDK动态代理

    六、参考资料

    项目源码已经上传,欢迎点击下载~

    先将自己总结的Java动态代理UML图放在前面,用相同的颜色代表同一个或本质上相同的类与方法,便于大家理解。接口UserService是我们自己定义的接口——接口中有方法execute();被代理类是实现了该接口的具体类;代理类则是存在于内存中,也实现了UserService接口的类,在内存中,该类名为$Proxy0。


        下面进入正文,今天想跟大家分享一下我自己在学习Java动态代理过程中的理解与收获,最后用自己的代码模拟实现JDK的动态代理。

    一、什么叫代理?

        这个概念不是我想表达的重点,所以这里我引用别人一篇博文的例子

        “动态代理技术就是用来产生一个对象的代理对象的。在开发中为什么需要为一个对象产生代理对象呢?
        举一个现实生活中的例子:歌星或者明星都有一个自己的经纪人,这个经纪人就是他们的代理人,当我们需要找明星表演时,不能直接找到该明星,只能是找明星的代理人。比如刘德华在现实生活中非常有名,会唱歌,会跳舞,会拍戏,刘德华在没有出名之前,我们可以直接找他唱歌,跳舞,拍戏,刘德华出名之后,他干的第一件事就是找一个经纪人,这个经纪人就是刘德华的代理人(代理),当我们需要找刘德华表演时,不能直接找到刘德华了(刘德华说,你找我代理人商谈具体事宜吧!),只能是找刘德华的代理人,因此刘德华这个代理人存在的价值就是拦截我们对刘德华的直接访问!
        这个现实中的例子和我们在开发中是一样的,我们在开发中之所以要产生一个对象的代理对象,主要用于拦截对真实业务对象的访问。那么代理对象应该具有什么方法呢?代理对象应该具有和目标对象相同的方法

        所以在这里明确代理对象的两个概念:

         1、代理对象存在的价值主要用于拦截对真实业务对象的访问。(事务的开启与关闭)

        2、代理对象应该具有和目标对象(真实业务对象)相同的方法。(要求实现同一接口)

        刘德华(真实业务对象)会唱歌,会跳舞,会拍戏,我们现在不能直接找他唱歌,跳舞,拍戏了,只能找他的代理人(代理对象)唱歌,跳舞,拍戏,一个人要想成为刘德华的代理人,那么他必须具有和刘德华一样的行为(会唱歌,会跳舞,会拍戏),刘德华有什么方法,他(代理人)就要有什么方法,我们找刘德华的代理人唱歌,跳舞,拍戏,但是代理人不是真的懂得唱歌,跳舞,拍戏的,真正懂得唱歌,跳舞,拍戏的是刘德华,在现实中的例子就是我们要找刘德华唱歌,跳舞,拍戏,那么只能先找他的经纪人,交钱给他的经纪人,然后经纪人再让刘德华去唱歌,跳舞,拍戏。”

    二、什么叫动态代理?

        代理类在程序运行时创建的代理方式被成为动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。

    三、动态代理有什么优势?

        通过使用代理,通常有两个优点:

        优点一:可以隐藏被代理类的实现;

        优点二:可以实现客户与被代理类间的解耦,在不修改被代理类代码的情况下能够做一些额外的处理。

    四、动态代理的JDK实现原理

        在java的动态代理机制中,有两个重要的类和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。当然,我还想带各位深入了解一下存在于JVM中神秘的动态代理类——$Proxy0。最后再给出java动态代理的经典使用流程。

    4.1 核心类/接口

    4.1.1 java.lang.reflect.Proxy类

        Proxy类提供了用于创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

    public class Proxy
    extends Object
    implements Serializable

        (1)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静态方法newProxyInstance

    public static Object newProxyInstance(ClassLoader loader, 
                Class<?>[] interfaces, 
                InvocationHandler h) 
                throws IllegalArgumentException { 
    
        // 检查 h 不为空,否则抛异常
        if (h == null) { 
            throw new NullPointerException(); 
        } 
    
        // 获得与制定类装载器和一组接口相关的代理类类型对象
        /*
         * Look up or generate the designated proxy class.
         */
            Class<?> cl = getProxyClass0(loader, interfaces); 
    
        // 通过反射获取构造函数对象并生成代理类实例
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                SecurityManager sm = System.getSecurityManager();
                if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                    // create proxy instance with doPrivilege as the proxy class may
                    // implement non-public interfaces that requires a special permission
                    return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        public Object run() {
                            return newInstance(cons, ih);
                        }
                    });
                } else {
                    return newInstance(cons, ih);
                }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        } 
        }
    
    private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
            try {
                return cons.newInstance(new Object[] {h} );
            } catch (IllegalAccessException e) {
                throw new InternalError(e.toString());
            } catch (InstantiationException e) {
                throw new InternalError(e.toString());
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString());
                }
            }
        }

        这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义。

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    
    //loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    //interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    //h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
    

        官方JDK文档给出了使用该方法创建一个动态代理类的模板:

    Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                              new Class[] { Foo.class },
                                              handler);
        动态代理真正的关键是在 getProxyClass0 方法。这个我们在后面手动实现模拟JDK动态代码的时候可以看到。

    4.1.2  java.lang.reflect.InvocationHandler接口

        每一个动态代理类中都有一个实现了InvocationHandler这个接口(代码中的中介)的实例handler类(即前言中的MyInvocationHandler类),当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。

    import java.lang.reflect.Method;
    
    public interface MyInvocationHandler {
    
        Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    
    }
        我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    //proxy:  内存中的代理实例 $proxy0
    //method:  内存代理实例中class.forName("被代理类").getMethod("目标方法") 即被代理的类的方法对象
    //args:  指代的是调用真实对象某个方法时接受的参数

        我们怎么确认上面几个参数就是这个意思呢?那就看看下面这节吧~

    4.2 代理类$Proxy0解析

    (1)为什么内存中的动态代理类叫做$Proxy0?


        这个可以通过断点查看到~

    (2)怎么拿到动态代理类的字节码文件?

      public static void createProxyFile() throws IOException {
            byte[] generateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class<?>[]{UserService.class});
    
            FileOutputStream outputStream = new FileOutputStream("$Proxy0.class");
            outputStream.write(generateProxyClass);
            outputStream.close();
        }
        在4.3 (5)中最终输出动态代理类执行结果后可以调用上面的方法,即可得到字节码文件

    (3)动态代理类$Proxy0字节码文件解析


        很清楚,动态代理类实现了UserService接口,继承了Proxy类

        首先我们看左边为动态代理类的代码结构。

    • 构造方法
    //$Proxy类
    public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
    }
    //父类Proxy
    protected InvocationHandler h;
    protected Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
    }

        可以看到动态代理类包含一个有参构造方法,内部调用了父类方法,其实也就是完成了调用处理器 InvocationHandler的实例化。该构造方法大家可得注意,在4.3(6)中提到的动态代理创建流程第3步,使用JAVA反射机制获取动态代理对象时:

    Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
        就是为了调用本构造方法。

    • Object方法

        大家可以看到动态代理类有m0~m3四个方法,这四个方法分别是什么呢?

    static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("proxy.test.UserService").getMethod("execute");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }

        可以看到,通过java反射机制,除了m3是UserService接口方法的实现以外,其他方法都是Object的方法。那这些方法有什么特点呢?

    public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
        其实核心就一句话 h.invoke() 也就是说动态代理类中的方法都使用了java反射机制去调用 调用处理器 InvocationHandler中的方法。

    • 接口方法

        接口方法与Object方法一样,内部就一句话。我们注意到,invoke方法传入3个参数,这个invoke方法也就是4.1.2中我们提到的InvocationHandler接口的 invoke方法,那理解3个参数的意义也就很简单了。

        参数1传入的为this——即$Proxy0本身,所以是内存中的动态代理对象

       参数2传入的为m3——也就是proxy.test.UserService中名为execute的方法,即接口中的方法。而这也完全证实了之前在“一、什么是代理?”部分提到的第二个特点——代理对象应该具有和目标对象(真实业务对象)相同的方法。(要求实现同一接口)

        参数3传入的为null——因为execute方法没有参数,所以为空。

    public final String execute() throws  {
            try {
                return (String)super.h.invoke(this, m3, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }

    4.3 动态代理的经典使用

    (1)理解UML图


        再把本图放上来暖场~JAVA中动态代理的使用基本就是如上图所示。下图是我们程序的目录结构,下面我们用代码来实现。


    (2)定义对象的行为接口UserService

    package proxy.test;
    
    public interface UserService {
    
        public String execute() throws Throwable ;
    }
    (3)定义目标业务对象类UserServiceImpl
    package proxy.test;
    
    public class UserServiceImpl implements UserService{
        @Override
        public String execute() throws Throwable {
            System.out.println("step 2 执行方法啦!!");
            return "step 2 执行方法啦!!";
        }
    }

    (4)自定义“调用处理程序”——MyInvocationHandler

    package proxy.test;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
    
        private UserService userService;
    
        public MyInvocationHandler(UserService userService) {
            this.userService = userService;
        }
        
        /*
        * @proxy 内存中的代理实例 $proxy0
        * @method 内存代理实例中class.forName("被代理类").getMethod("目标方法") 即被代理的类的方法对象
        * @args 方法参数
        * */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();   //事务开启
    
            method.invoke(userService, args);
    
            after();    //事务关闭
    
            return "成功了";
        }
    
        private void before() {
            System.out.println("事务开启!");
        }
    
        private void after() {
            System.out.println("事务关闭");
        }
    }
        动态代理最具魅力所在——也就是上面代码中事务开启和关闭部分,总结起来就是: 实现了方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以 添加调用日志,做事务控制等。

    (5)代理类生成并测试代码

    package proxy.test;
    import java.lang.reflect.Proxy;
    
    public class MyTest {
    
        public static void main(String[] args) throws Throwable {
            System.out.println("---------------JDK动态代理----------------");
            UserService userService = (UserService) Proxy.newProxyInstance(MyTest.class.getClassLoader(),
                    new Class<?>[]{UserService.class},
                    new MyInvocationHandler(new UserServiceImpl()));
    
            userService.execute();
        }
    }

        上面的代码也就是4.1.1(3)中提到的JDK文档给出的创建代理类方式。通过强制类型转换并执行相应方法,得到输出如下:


    (6)动态代理创建流程总结

        动态代理的创建是基于java反射的,一个典型的动态代理创建对象过程可分为以下四个步骤:

    • 1.通过实现InvocationHandler接口创建自己的调用处理器 
            InvocationHandler handler = new InvocationHandlerImpl(...);
    • 2.通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
            Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
    • 3.通过反射机制获取动态代理类$Proxy0的构造函数,其参数类型是调用处理器接口类型
            Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
    • 4.通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
            Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

        为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。生成的动态代理类$Proxy0继承Proxy类实现UserService接口,实现的UserService的方法实际调用调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))。

    (7)JDK动态代理的不足

        诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。摆脱这个遗憾就得依靠CGLIB(此处等待下文)。

    五、手写代码模拟JDK动态代理

    5.1 原理解析

        手撸代码模拟JDK动态代理,其实也就是对java.lang.reflect.Proxy类的功能进行模拟。其步骤主要有以下四步:

    (1)创建代理类的源码; 

        拿到被代理类(如UserServiceImpl)实现的接口类对象(如UserService.class),遍历里面的方法(如execute()方法),以字符串的形式拼凑出代理类源码(动态代理类与被代理类实现同一接口在此体现),将代理类的源码写到本地java文件

    (2)将源码进行编译成字节码; 

        读取源码,编译java文件,得到.class字节码文件(的路径)

    (3)将字节码加载到内存; 

    (4)实例化代理类对象并返回给调用者。

        其中步骤(1)、(2)、(3)就是我们自定义的Proxy类所要完成的功能,类的结构如下图;步骤(4)是我们功能代码/测试代码要实现的。下面我们对每一步进行解析。


    5.2 创建代理类的源码

    项目实现源码已经上传,欢迎点击下载~

    (1)使用字符串拼凑动态代理对象的java源码

     //用字符串的形式拼凑出内存里的代理类
        static String rt = "\r\n";
        private static String get$Proxy0(Class<?> interfaces) {
    
            Method[] methods = interfaces.getMethods();
    
            String proxyClass = "package proxy;" + rt
                    + "import java.lang.reflect.Method;" + rt
                    + "public class $Proxy0 implements " + interfaces.getName() + "{"
                    + rt + "MyInvocationHandler h;" + rt
                    + "public $Proxy0(MyInvocationHandler h) {" + rt
                    + "this.h = h;" + rt + "}" + getMethodString(methods, interfaces)
                    + rt + "}";
            return proxyClass;
        }
    
        private static String getMethodString(Method[] methods, Class<?> interfaces) {
            String proxyMethod = "";
    
            for (Method method : methods) {
                proxyMethod += "public String " + method.getName()
                        + "() throws Throwable {" + rt + "Method md = "
                        + interfaces.getName() + ".class.getMethod(\"" + method.getName()
                        + "\",new Class[]{});" + rt
                        + "return (String)this.h.invoke(this, md, null);" + rt + "}" + rt;
            }
    
            return proxyMethod;
        }
        上面这段代码所模拟的具体代码实现在JDK中是在jar包中的,其得到的结果就是生成了$Proxy0.java
    package proxy;
    import java.lang.reflect.Method;
    
    public class $Proxy0 implements proxy.test.UserService{
        MyInvocationHandler h;
        public $Proxy0(MyInvocationHandler h) {
            this.h = h;
        }
        
        public String execute() throws Throwable {
            Method md = proxy.test.UserService.class.getMethod("execute",new Class[]{});
            return (String)this.h.invoke(this, md, null);
        }
    }

    (2)将源码写入本地文件

     private static void outputFile(String proxyClass, String path) {
            File f = new File(path);
            try {
                FileWriter fw = new FileWriter(f);
                fw.write(proxyClass);
                fw.flush();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    5.3 将源码进行编译成字节码

    private static void compileJavaFile(String fileName) {
            try {
                //获得当前系统中的编译器
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                //获得文件管理者
                StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
                Iterable<? extends JavaFileObject> fileObjects = manager.getJavaFileObjects(fileName);
                //编译任务
                JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, fileObjects);
                //开始编译,执行完可在当前目录下看到.class文件
                task.call();
                //关闭文件管理者
                manager.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        这段代码用的都是JAVA自带的编译工具,不做过多解释。

    5.4 将字节码加载到内存

    private static Object loadClassToJvm(MyInvocationHandler h) {
            try {
                //使用自定义类加载器
                MyClassLoader loader = new MyClassLoader("C:\\HailinLuo\\CODING\\JAVA\\JavaProgramming\\src\\proxy");
                //得到动态代理类的反射对象
                Class<?> $Proxy0 = loader.findClass("$Proxy0");
                //通过反射机制获取动态代理类$Proxy0的构造函数,其参数类型是调用处理器接口类型
                Constructor<?> constructors = $Proxy0.getConstructor(MyInvocationHandler.class);
                //通过构造函数创建动态代理类实例
                return constructors.newInstance(h);
            } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }

        这里使用了自定义的类加载器MyClassLoader 

    package proxy;
    
    import java.io.*;
    
    public class MyClassLoader extends ClassLoader {
        File dir;
        //把文件路径用构造函数传进来
        public MyClassLoader(String path) {
            dir = new File(path);
        }
        /*
         * 本方法就是去加载对应的字节码文件
         * */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            //如果文件路径可用
            if (dir != null) {
                File clazzFile = new File(dir, name + ".class");
                //如果字节码文件存在
                if (clazzFile.exists()) {
                    //把字节码文件加载到VM
                    try {
                        //文件流对接class文件
                        FileInputStream inputStream = new FileInputStream(clazzFile);
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        byte[] buffer = new byte[1024];
                        int len;
                        //将class文件读取到buffer中
                        while ((len = inputStream.read(buffer)) != -1) {
                            //将buffer中的内容读取到baos中的buffer
                            baos.write(buffer, 0, len);
                        }
                        //将buffer中的字节读到内存加载为class
                        return defineClass("proxy." + name, baos.toByteArray(), 0, baos.size());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return super.findClass(name);
        }
    }

        也可以使用URLClassLoader 加载,如下所示

    //load到内存
            URL[] urls = new URL[]{new URL("C:\\HailinLuo\\CODING\\JAVA\\JavaProgramming\\src\\proxy")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class cls = urlClassLoader.loadClass("proxy.$Proxy0");

    5.5 实例化代理类对象并返回给调用者

    UserService service = (UserService) MyProxy.newProxyInstance(MyTest.class.getClassLoader(),
                    UserService.class,
                    new MyInvocationHandlerImpl(new UserServiceImpl()));
    
            service.execute();

        没什么好说的。。。

    5.6 输出结果


        如上图所示,下方红框所示输出结果与JDK动态代理效果一致。说明我们的模拟是成功的!而上面那个红框中的$Proxy0.java和$Proxy0.class则是5.2(生成源码)与5.3(编译为字节码)执行的结果。

        OK,分享就到这里~

    六、参考资料

    项目源码已经上传,欢迎点击下载~

    http://www.jb51.net/article/86531.htm

    https://blog.csdn.net/pangqiandou/article/details/52964066

    https://blog.csdn.net/scplove/article/details/52451899

    https://www.jianshu.com/p/dbce090d5c3e?1487292535486

    https://blog.csdn.net/ljt2724960661/article/details/52507314


    展开全文
  • 演示了Java动态代理技术,学习查看详细的实现细节,更多代码的说明请参考博客文章 :http://520code.net/index.php/archives/19/
  • java jdk动态代理和cglib动态代理对比,实现,区别 jdk动态代理和cglib动态代理对比 jdk动态代理 特点 Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷; Proxy:Proxy类是动态产生的,这个类...

    java jdk动态代理和cglib动态代理对比,实现,区别

    jdk动态代理和cglib动态代理对比

    jdk动态代理

    特点

    1. Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷;
    2. Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上;
    3. Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来。
    4. InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。

    总结

    • JDK动态代理类实现了InvocationHandler接口,重写的invoke方法。
    • JDK动态代理的基础是反射机制(method.invoke(对象,参数))Proxy.newProxyInstance()
    cglib动态代理

    特点

    1. 原理是对指定的目标生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    注意:jdk的动态代理只可以为接口去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。

    代码实现

      公共代码部分

    //接口类
    public interface FoodService {
        public void makeNoodle();
        public void makeChicken();
    }
    
    //实现接口
    public class FoodServiceImpl implements FoodService {
        @Override
        public void makeNoodle() {
            System.out.println("make noodle");
        }
    
        @Override
        public void makeChicken() {
            System.out.println("make Chicken");
        }
    }
    

    jdk动态代理

      jdk动态代理代码

    public class JDKProxyFactory implements InvocationHandler {
        private Object target;
    
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        // 创建代理对象
        public Object createProxy() {
            // 1.得到目标对象的类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
            // 2.得到目标对象的实现接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
            // 3.第三个参数需要一个实现invocationHandler接口的对象
            Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
            return newProxyInstance;
        }
    
    
        // 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("这是增强方法前......");
            Object invoke = method.invoke(target, args);
            System.out.println("这是增强方法后......");
            return invoke;
        }
    
        public static void main(String[] args) {
            // 1.创建对象
            FoodServiceImpl foodService = new FoodServiceImpl();
            // 2.创建代理对象
            JDKProxyFactory proxy = new JDKProxyFactory(foodService);
            // 3.调用代理对象的增强方法,得到增强后的对象
            FoodService createProxy = (FoodService) proxy.createProxy();
            createProxy.makeChicken();
        }
    
    }
    

    cglib动态代理

      cglib动态代理代码

    public class CglibProxyFactory implements MethodInterceptor {
        //得到目标对象
        private Object target;
    
        //使用构造方法传递目标对象
        public CglibProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        //创建代理对象
        public Object createProxy(){
            //1.创建Enhancer
            Enhancer enhancer = new Enhancer();
            //2.传递目标对象的class
            enhancer.setSuperclass(target.getClass());
            //3.设置回调操作
            enhancer.setCallback(this);
    
            return enhancer.create();
        }
    
    
        //参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("这是增强方法前......");
            Object invoke = methodProxy.invoke(target, args);
            System.out.println("这是增强方法后......");
            return invoke;
        }
    
        public static void main(String[] args) {
            // 1.创建对象
            FoodServiceImpl foodService = new FoodServiceImpl();
            // 2.创建代理对象
            CglibProxyFactory proxy = new CglibProxyFactory(foodService);
            // 3.调用代理对象的增强方法,得到增强后的对象
            FoodService createProxy = (FoodService) proxy.createProxy();
            createProxy.makeChicken();
        }
    }
    
    
    展开全文
  • 本地debug的时候,可以实时编译并更新代码,线上也可以不停服来动态更新类,即所说的java热部署。  JDK代理的两种方式:  1.premain方式是Java SE5开始提供的代理方式,但其必须在命令行指定代理jar,并且代理类...
  • 上篇介绍了一下静态代理Java中的代理模式——静态代理以及分析静态代理的缺点 也分析了一下静态代理的缺点: 1、由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要...

    视频功能审核通过了,可以看视频啦!记得点关注啊~

    注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了

    记得点关注啊,视频里的wx二维码失效了,wx搜索:“聊5毛钱的java 或 扫码关注公众号,欢迎一起学习交流

    快扫码关注啦!关注可领取博主的Java学习视频+资料,保证都是干货

    SpringAOP系列,帮你了解SpringAOP的来龙去脉

    上篇介绍了一下静态代理:Java中的代理模式——静态代理以及分析静态代理的缺点

    静态代理是程序运行前,代理类的.class文件已经存在了。

    动态代理是,在程序运行时运用反射机制动态创建而成,无需手动编写代码

    也分析了一下静态代理的缺点:

    1、由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要创建100个代理类

    2、如果一个Service中有很多方法需要事务(增强动作),发现代理对象的方法中还是有很多重复的代码

    3、由第一点和第二点可以得出:静态代理的重用性不强

    那怎么解决呢?

    用动态代理就可以很好的解决上述问题,本篇介绍一下:Java中的动态代理

    动态代理实现的目的和静态代理一样,都是对目标方法进行增强,而且让增强的动作和目标动作分开,达到解耦的目的

    动态代理分为JDK的动态代理和cglib动态代理

    它俩有略微的差别:JDK动态代理产生的代理类和目标类实现了相同的接口;cglib动态代理产生的代理类是目标对象的子类

    下面分别介绍JDK的动态代理(是JDK的代码实现的)和cglib动态代理(是cglib的jar包实现的)

    1、JDK的动态代理

    package com.cj.study.proxyjdk;
    
    public interface PersonService {
    	
    	public String savePerson();
    	
    	public void updatePerson();
    	
    	public void deletePerson();
    	
    }
    package com.cj.study.proxyjdk;
    
    public class PersonServiceImpl implements PersonService{
    
    	@Override
    	public String savePerson() {
    		System.out.println("添加");
    		return "保存成功!";
    	}
    
    	@Override
    	public void updatePerson() {
    		System.out.println("修改");
    	}
    
    	@Override
    	public void deletePerson() {
    		System.out.println("删除");
    	}
    
    }
    
    package com.cj.study.proxyjdk;
    
    public class MyTransaction {
    	public void beginTransaction(){
    		System.out.println("开启事务 ");
    	}
    	public void commit(){
    		System.out.println("提交事务");
    	}
    }
    

    注意:在动态代理在生成代理对象的时候需要一个拦截器 InvocationHandler 因此咱们需要写一个拦截器

    package com.cj.study.proxyjdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class PersonServiceInterceptor implements InvocationHandler{
    	//目标类
    	private Object target;
    	//增强类
    	private MyTransaction myTransaction;
    	//构造函数注入目标类和增强类
    	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
    		this.target = target;
    		this.myTransaction = myTransaction;
    	}
    
    	//代理类的每一个方法被调用的时候都会调用下边的这个invoke方法
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		this.myTransaction.beginTransaction();
    		Object returnValue = method.invoke(this.target, args);
    		this.myTransaction.commit();
    		return returnValue;
    	}
    	
    }
    

    注意:

    1、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体

    2、拦截器中invoke方法体的内容就是代理对象方法体的内容

    3、拦截器中invoke方法的method参数是在调用的时候赋值的

    package com.cj.study.proxyjdk;
    
    import java.lang.reflect.Proxy;
    import org.junit.Test;
    
    public class ProxyTest {
    	@Test
    	public void test(){
    		Object target = new PersonServiceImpl();
    		MyTransaction myTransaction = new MyTransaction();
    		PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction);
    		PersonService personService = (PersonService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),interceptor);
    		String returnValue = (String)personService.savePerson();
    		System.out.println(returnValue);
    	}
    }
    

    可以打断点看下

    发现生成的对象是 $Proxy4 说明返回的已经是我们的代理对象了

    最后的运行结果

    2、cglib动态代理

    首先需要导入cglib的jar包:cglib-nodep-2.1_3.jar

    package com.cj.study.proxycglib;
    
    public interface PersonService {
    	
    	public String savePerson();
    	
    	public void updatePerson();
    	
    	public void deletePerson();
    	
    }
    
    package com.cj.study.proxycglib;
    
    public class PersonServiceImpl implements PersonService{
    
    	@Override
    	public String savePerson() {
    		System.out.println("添加");
    		return "保存成功!";
    	}
    
    	@Override
    	public void updatePerson() {
    		System.out.println("修改");
    	}
    
    	@Override
    	public void deletePerson() {
    		System.out.println("删除");
    	}
    
    }
    
    package com.cj.study.proxycglib;
    
    public class MyTransaction {
    	public void beginTransaction(){
    		System.out.println("开启事务 ");
    	}
    	public void commit(){
    		System.out.println("提交事务");
    	}
    }
    
    package com.cj.study.proxycglib;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class PersonServiceInterceptor implements MethodInterceptor{
    	//目标类
    	private Object target;
    	//增强类
    	private MyTransaction myTransaction;
    	//构造函数注入目标类和增强类
    	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
    		this.target = target;
    		this.myTransaction = myTransaction;
    	}
    	
    	public Object createProxy(){
    		Enhancer enhancer = new Enhancer();
    		enhancer.setCallback(this);
    		enhancer.setSuperclass(this.target.getClass());
    		return enhancer.create();
    	}
    
    	@Override
    	public Object intercept(Object arg0, Method arg1, Object[] arg2,
    			MethodProxy arg3) throws Throwable {
    		myTransaction.beginTransaction();
    		Object returnValue = arg1.invoke(this.target, arg2);
    		myTransaction.commit();
    		return returnValue;
    	}
    	
    }
    
    package com.cj.study.proxycglib;
    
    import org.junit.Test;
    
    public class ProxyTest {
    	@Test
    	public void test(){
    		Object target = new PersonServiceImpl();
    		MyTransaction myTransaction = new MyTransaction();
    		PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction);
    		PersonService personService =(PersonService) interceptor.createProxy();
    		String returnValue = (String)personService.savePerson();
    		System.out.println(returnValue);
    	}
    }
    

    最后的运行结果

    最后需要知道的点:

    1、JDK动态代理,要求目标类实现接口,但是有时候目标类直接一个单独的对象,并没有实现任何的接口,这时就得使用CGLib动态代理
    2、JDK动态代理是JDK里自带的,CGLib动态代理需要引入第三方的jar包

    3、CGLib动态代理,它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展
    4、CGLib动态代理,是基于继承来实现代理,所以无法对final类、private方法和static方法进行代理

    以上就是动态代理的两种实现。

    我们用上边的做法去实现目标方法的增强,实现代码的解耦,是没有问题的,但是还是需要自己去生成代理对象,自己手写拦截器,在拦截器里自己手动的去把要增强的内容和目标方法结合起来,这用起来还是有点繁琐,有更好的解决方案吗?

    答案是:有的!那就是Spring的AOP,这才是咱们最终想引出来的重点!

    有了Spring的AOP后,就不用自己去写了,只需要在配置文件里进行配置,配置好后Spring按照你的配置去帮你生成代理对象,按照你的配置把增强的内容和目标方法结合起来。就相当于自己写代码也能实现和aop类似的功能,但是有了Spring aop以后有些事情Spring帮你做了,而且人家Spring做成了可配置化,用起来非常简单而且很灵活

    咱们上边用的JDK动态代理和cglib动态代理,这两种在Spring的AOP里都有用到,Spring是根据不同的情况去决定是使用JDK的动态代理生成代理对象,还是使用cglib去生成代理对象,具体的内容下一篇会讲到。

    下一篇我们继续:讲一下Spring中的AOP以及切入点表达式和各种通知

    铁子们,如果觉得文章对你有所帮助,可以点关注,点赞

    也可以关注下公众号:扫码或 wx搜索:“聊5毛钱的java”,欢迎一起学习交流,关注公众号可领取博主的Java学习视频+资料,保证都是干货

    3Q~

    纯手敲原创不易,如果觉得对你有帮助,可以打赏支持一下,哈哈,感谢~

               

    展开全文
  • Java动态代理分析

    万次阅读 多人点赞 2017-04-12 20:27:16
    Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地制定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分配到委托对象上反射执行,配置执行过程中,开发人员还...

    Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地制定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分配到委托对象上反射执行,配置执行过程中,开发人员还可以进行修改

    代理设计模式

    代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息、过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
    1. 为了保持行为的一致性,代理类和委托类通常会实现相同的接口
    2. 引入代理能够控制对委托对象的直接访问,可以很好的隐藏和保护委托对象,也更加具有灵活性

    相关的类和接口

    要了解 Java 动态代理的机制,首先需要了解以下相关的类或接口:
    1. java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象
    2. java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个invoke方法,用于几种处理在动态代理类对象上的方法调用。通常在该方法中实现对委托类的代理访问。
    3. java.lang.ClassLoader:Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个.class 文件中。

    代理机制及其特点

    首先让我们来了解一下如何使用 Java 动态代理。具体有如下四步骤:
    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

    // InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
    // 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
    InvocationHandler handler = new InvocationHandlerImpl(..); 
    
    // 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
    Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
    
    // 通过反射从生成的类对象获得构造函数对象
    Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
    
    // 通过构造函数对象创建动态代理类实例
    Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

    实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如下

    // InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
    InvocationHandler handler = new InvocationHandlerImpl(..); 
    
    // 通过 Proxy 直接创建动态代理类实例
    Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, 
         new Class[] { Interface.class }, 
         handler );

    特点

    动态生成的代理类本身的一些特点
    1. 包:如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空),如果所代理的接口中有非 public 的接口(因为接口不能被定义为 protect或private,所以除 public之外就是默认的package访问级别,那么它将被定义在该接口所在包,这样设计的目的是为了最大程度的保证动态代理类不会因为包管理的问题而无法被成功定义并访问;
    2. 类修饰符:该代理类具有 final 和 public 修饰符,意味着它可以被所有的类访问,但是不能被再度继承;
    3. 类名:格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类,值得注意的一点是,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,这样可以节省不必要的代码重复生成,提高了代理类的创建效率。
    4. 类继承关系:Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且该类还实现了其所代理的一组接口;
    这里写图片描述
    代理类实例的一些特点
    1. 每个实例都会关联一个InvocationHandler(调用处理器对象),在代理类实例上调用其代理接口中声明的方法时,最终都会由InvocationHandler的invoke方法执行;
    2. java.lang.Object中有三个方法也同样会被分派到调用处理器的 invoke 方法执行,它们是 hashCode,equals 和 toString;

    被代理接口的一组特点
    1. 要注意不能有重复的接口
    2. 接口对于类装载器必须可见,否则类装载器将无法链接它们
    3. 被代理的所有非 public 的接口必须在同一个包中,接口的数目不能超过65535

    美中不足

    Proxy只能对interface进行代理,无法实现对class的动态代理。观察动态生成的代理继承关系图可知原因,他们已经有一个固定的父类叫做Proxy,Java语法限定其不能再继承其他的父类

    代码示例

    最后以一个简单的动态代理例子结束

    public class DynamicProxy {
        interface IHello{
            void sayHello();
        }
    
        static class Hello implements IHello{
            public void sayHello() {
                System.out.println("hello world");
            }
        }
    
        static class DynamicProxyTest implements InvocationHandler{
            Object originalObj;
            Object bind(Object originalObj){
                this.originalObj = originalObj;
                return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(),
                        originalObj.getClass().getInterfaces(),this);
            }
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Welcome");
                return method.invoke(originalObj,args);
            }
        }
    
        public static void main(String[] args){
            //设置这个值,在程序运行完成后,可以生成代理类
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
            IHello hello = (IHello) new DynamicProxyTest().bind(new Hello());
            hello.sayHello();
        }
    }

    程序输出为:

    Welcome
    hello world

    注:本文是根据IBM中developerworks上的文章整理而成,原文链接https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/

    展开全文
  • 轻松学,Java 中的代理模式及动态代理

    万次阅读 多人点赞 2017-06-29 22:08:55
    前几天我写了《秒懂,Java 注解 (Annotation)你可以这样学》,因为注解其实算反射技术中的一部分,然后我想了一下,反射技术中还有个常见的概念就是动态代理,于是索性再写一篇关于动态代理的博文好了。...
  • Java两种动态代理JDK动态代理和CGLIB动态代理

    万次阅读 多人点赞 2018-08-07 15:33:35
    JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是...
  • 什么是Java动态代理,如何实现一个动态代理例子

    千次阅读 多人点赞 2019-09-04 11:06:15
    Java动态代理 一、概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说...
  • Java JDK 动态代理(AOP)使用及实现原理分析

    万次阅读 多人点赞 2019-05-08 21:28:06
    二、Java 动态代理类 三、JDK的动态代理怎么使用? 四、动态代理怎么实现的? 五、结论 一、什么是代理代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为...
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解动态代理原理,对学习AOP框架至关重要。 JDK动态代理不需要任何外部依赖,但是只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有...
  • Java动态代理实现数据源连接池,用代理类实现的连接池代码,绝对完整的案例,下载源码就能跑起来!Java动态代理实现数据源连接池,用代理类实现的连接池代码
  • Java JDK 动态代理实现和代码分析

    千次阅读 2021-06-02 20:51:44
    JDK 动态代理 API5.1 java.lang.reflect.Proxy5.1 java.lang.reflect.InvocationHandler二、JDK 动态代理的实现(代码)1. 项目结构图2. IRentService 接口3. LandlordServiceImpl 真实类4. ...
  • Java知识体系最强总结(2021版)

    万次阅读 多人点赞 2019-12-18 10:09:56
    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同...
  • java动态代理代码

    2008-10-16 02:10:15
    eclipse工发工具可以直接打开,从代理原理到动态代理总共分成三个Demo
  • 通过代理实现Java代码访问指定URL

    千次阅读 2017-09-06 19:12:03
    package network.openURL;...import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import j
  • java动态代理详解

    万次阅读 多人点赞 2018-08-21 15:32:51
    目前java动态代理的实现分为两种 1.基于JDK的动态代理 2.基于CGILB的动态代理 在业务中使用动态代理,一般是为了给需要实现的方法添加预处理或者添加后续操作,但是不干预实现类的正常业务,把一些基本业务和主要...
  • java动态代理实现

    千次阅读 2019-01-15 14:42:46
    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理动态代理。  一、代理模式  代理模式是常用的java设计模式,他的特征是...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的...
  • JAVA中的动态代理

    千次阅读 2018-07-28 14:30:33
    代理模式 &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 代理模式的英文叫做Proxy或Surrogate,中文都可译为“代理”,所谓代理,就是一个人或者一个机构代表另一个人...
  • 秒懂Java代理动态代理模式

    万次阅读 多人点赞 2018-06-30 17:08:23
    什么是动态代理模式?二者什么关系?具体如何实现?什么原理?如何改进?这即为我们学习一项新知识的正确打开方式,我们接下来会以此展开,让你秒懂。 概念 什么是代理模式 定义:为其他对象提供一种代理以控制...
  • 之前本人在设计模式中有写过静态代理动态代理的相关代码测试,可以看下。 今天我们主要学一下理论相关知识。 静态代理动态代理动态代理模式主要由四个元素共同组成: 接口:定义具体实现的方法 被代理类:...
  • Java动态代理内存中生成的$Proxy0类
  • java CGLIB动态代理

    千次阅读 2019-05-01 22:20:26
    CGLIB动态代理 一:CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。 二:使用cglib需要引入cglib的jar包,如果你已经有...
  • Java动态代理的实现原理

    万次阅读 多人点赞 2018-09-25 11:20:57
    静态代理 动态代理 基于JDK的动态代理 基于继承的动态代理

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 354,238
精华内容 141,695
关键字:

动态代理java代码

java 订阅