• jQuery火箭图标返回顶部代码


    0. 前言

    学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,它利用的是反射机制,依赖注入就不用多说了,而对于Spring的核心AOP来说,使用了动态代理,所以本篇随笔就是对java的动态代理进行一个回顾

    1. 代理模式

    代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

    2. 静态代理

    由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。缺点:代理类和被代理类编译期间都写死了,不够灵活

    package com.zad.java;
    
    /**
     *
     * 静态代理举例
     * 代理类和被代理类编译期间都写死了,不够灵活
     */
    
    interface smile{
        void produceCloth();
    }
    
    /**代理类**/
    class ProxyClothFactory implements smile{
    
        private smile factory;//用被代理类对象进行实例化
    
        public ProxyClothFactory(smile factory){
            this.factory = factory;
        }
    
        @Override
        public void produceCloth() {
            System.out.println("你真的");
            factory.produceCloth();
            System.out.println("是不是");
        }
    
    }
    
    //被代理类
    class realsmile implements smile{
    
        @Override
        public void produceCloth() {
            System.out.println("很开心");
        }
    }
    
    
    public class StaticProxyTest {
        public static void main(String[] args) {
            //创建被代理类对象
            realsmile real = new realsmile();
            //创建代理类对象
            ProxyClothFactory proxyClothFactory = new ProxyClothFactory(real);
            proxyClothFactory.produceCloth();
        }
    }

    3. 动态代理

    Java反射提供了一种类动态代理机制,可以通过代理接口实现类来完成程序无侵入式扩展。

    Java动态代理主要使用场景:

    1. 统计方法执行所耗时间。
    2. 在方法执行前后添加日志。
    3. 检测方法的参数或返回值。
    4. 方法访问权限控制。
    5. 方法Mock测试。

    创建动态代理类会使用到java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。java.lang.reflect.Proxy主要用于生成动态代理类Class、创建代理类实例。proxy类实现了java.io.Serializable接口

    InvocationHandler接口

    java.lang.reflect.InvocationHandler接口用于调用Proxy类生成的代理类方法,该类只有一个invoke方法,那么也必须要实现该方法,入口参数Object proxy即为要被代理的对象,method为被调用的方法,args为代理实例的方法参数数组,若没参数则为null

     proxy类

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

    loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    
    interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    
    h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
    package com.zad.java;
    
    import org.omg.CORBA.SystemException;
    import org.omg.CORBA.portable.InputStream;
    import org.omg.CORBA.portable.InvokeHandler;
    import org.omg.CORBA.portable.OutputStream;
    import org.omg.CORBA.portable.ResponseHandler;
    import sun.awt.AWTAccessor;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理举例
     *
     *
     * **/
    
    interface Human{
        String getBelief();
        void eat(String food);
    }
    //被代理类
    class SuperMan implements Human{
    
        @Override
        public String getBelief() {
            return "I believe I can fly!";
        }
    
        @Override
        public void eat(String food) {
            System.out.println("我喜欢吃"+food);
        }
    }
    
    /**
     *
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     *
     * 实现动态代理需要解决的问题:
     * 问题1:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
     * 问题2:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a
     */
    
    class ProxyFactory{
        //调用此方法,返回一个代理类的对象,解决了问题1
        public static Object getProxychInstance(Object obj){//obj:被代理类的对象
            MyInvocationHandler handler = new MyInvocationHandler();
            handler.bind(obj);
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
        }
    }
    class MyInvocationHandler implements InvocationHandler {
        private Object obj;
        public void bind (Object obj){
            this.obj = obj;
        }
    
        //当我们通过代理类的对象,调用方法a,就会自动调用如下方法:invoke()
        //将被代理类要执行的方法a的功能就声明在invoke()中
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //method:就是代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
            Object returnValue = method.invoke(obj, args);
            return returnValue;
        }
    
    }
    public class ProxyTest {
        public static void main(String[] args) {
            SuperMan superMan = new SuperMan();
            Human proxyInstance = (Human) ProxyFactory.getProxychInstance(superMan);
            proxyInstance.getBelief();
            proxyInstance.eat("麻辣烫");
    
        }
    }

    cglib代理

    这里我们先简单说一下这两种代理方式最大的区别,JDK动态代理是基于接口的方式,换句话来说就是代理类和目标类都实现同一个接口,那么代理类和目标类的方法名就一样了,这种方式上一篇说过了;CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法啊,这样也可以保证代理类拥有目标类的同名方法

    cglib特点:

    1. 可以代理没有实现接口的类
    2. 可以在运行期扩展java类与实现java接口,被许多aop框架所使用,例如spring AOP和dynaop提供方法的interception拦截

    cglib和动态代理的区别

    • 使用动态代理必须实现接口
    • cglib无需实现接口,达到代理类无侵入

     引入cglib的jar包(https://repo1.maven.org/maven2/cglib/cglib/3.2.5/cglib-3.2.5.jar)

    <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.5</version>
    </dependency>

    男的写了

  • 相关阅读:
    基于FFI模块CAPI与JavaScript的各种类型匹配总结
    在Electron中通过ffi模块实现JavaScript调用C++动态库
    谷歌地图OGC WMTS服务规则
    tiff/tfw, jpg/jpgw坐标文件的格式(6个参数)
    GreenDao 多表事务操作
    Asp.net WebAPI 使用流下载文件注意事项
    mvn 用指定setting.xml 执行指定pom.xml
    Swagger自动生成接口文档
    Windows下控制Nginx的状态
    Android 动态权限申请
  • 原文地址:https://www.cnblogs.com/kuaile1314/p/14209445.html
Copyright © 2020-2023  润新知