• Java动态代理


    1、java反射技术

    //【java.lang.reflect.*】 反射专用包
    
    // 反射:只要配置就能生成对象,解除程序耦合度,灵活,缺点是运行慢
    ReflectServiceImple1 obj1 = (ReflectServiceImple1)Class.forName("com.alison.ssm.ReflectServiceImple1").newInstance();  //无参构造
    ReflectServiceImple2 obj = (ReflectServiceImple2)Class.forName("com.alison.ssm.ReflectServiceImple2").getConstructor(String.class).newInstance("张三");    //有参构造
    // Class.forName()就是给类加载器注册一个全限定名,并使用newInstance()实例化对象
    
    // 反射方法
    Method method = ReflectServiceImple1.class.getMethod("sayHello", String.class);        // 先获得Class对象,再使用getMethod方法 得到Method实例
    Object retObj = method.invoke(new ReflectServiceImple1(), "alison");                    // 使用invoke激活方法,获得返回值,传入类实例和方法参数
    // 也可以这样实现:
    new ReflectServiceImple1().getClass().getMethod("sayHello", String.class)
    // 【注意】一定用try..catch结构包裹,因为容易爆ClassNotFound或者IllegalAccess等的异常

    2、动态代理

    动态代理的意义在于生成一个占位,又称代理对象,来代理真实对象,从而控制真实对象访问

    java中最常用的代理方式有 JDK, CGLIB, javassist, ASM等,常见前两种

    主要有两个步骤:

    1)代理对象与真实对象建立联系,生成代理对象

    2)实现代理对象的代理逻辑方法

    2.1 JDK动态代理

    使用JDK动态代理,需要实现java.lang.reflect.InovationHandler接口,实现invoke 方法

    // 真实操作类
    public interface HelloWorld{
        public void sayHelloWorld();
    }
    public class HelloWorldImp implements HelloWorld{
        @override
        public void sayHelloWorld(){
            System.out.println("Hello World!");
        }
    }
    
    //【JDK动态代理】
    // 需要实现java.lang.reflect.InvicationHandler接口,invoke()方法,且被代理类 必须有实现的接口!!  如 HelloWorldImp implements HelloWorld
    public class JDKProxyExample implements InvicationHandler {
        private Object target;
        /**
        *    建立代理关系,返回代理对象
        *    @param     target 真实对象
        *    @return    代理对象    
        */
        public Object bind(Object target){
            this.target = target;
            // 三个参数:真实类加载器,接口数组,当前代理类
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        /**
        *    代理逻辑方法:当使用代理对象调用某方法时,就会自动调用invoke方法
        *    @param     proxy 代理对象
        *    @param    method 当前调度方法
        *    @param    args 当前方法参数
        *    @return    代理结果返回
        *    @throws Trowable 异常
        */
        @override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入代理逻辑方法");
            System.out.println("在调用真实对象前的服务操作");
            Object obj = method.invoke(target, args);            // 反射启动·启用方法
            System.out.println("在调用真实对象后的服务操作");
            return obj;
        }
    }

    实现InvicationHandler 接口,主要有两个方法,bind用于和真实对象建立联系,返回代理对象,内部具体调用的是Proxy.newProxyInstance()方法,传入三个参数:类加载器,类接口(表示生成的动态代理对象挂在哪些接口下),当前类对象(必须实现invoke方法)

    invoke方法就是可以启动被代理对象的真实方法了,可以加入自己的逻辑,使用的就是方法反射;当使用代理对象调用某方法时,就会自动调用invoke方法

    测试:

        public void testJDKProxy(){
            JDKProxyExample jdk = new JDKProxyExample();
            HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImp());  // 此处需要强转下
            proxy.sayHelloWorld();    // 代理对象调用方法,会进入到代理类的invoke()方法中处理该方法
        }

     输出:

    进入代理逻辑方法
    在调用真实对象前的服务操作
    Hello World!
    在调用真实对象后的服务操作

     2.2 CGLIB动态代理

    JDK代理必须提供接口,针对无接口实现的类,可以使用CGLIB

    //【CGLIB动态代理】
    // 优势:不要求被代理类 必须实现某接口
    public class CglibProxyExample implements MethodInterceptor {
        /**
        *    生成CGLIB代理对象
        *    @param    cls ——Class类
        *    @return    Class类的CGLIB代理对象
        */
        public void getProxy(Class cls){
            //CGLIB enhancer增强类对象
            Enhancer enhancer = new Enhancer();
            // 设置增强类型
            enhancer.setSuperclass(cls);
            // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInteceptor犯法
            enhancer.setCallback(this);
            // 生成并返回代理对象
            return enhancer.create();
        }
        /**
        *    代理逻辑方法
        *    @param    methodProxy 方法代理
        *    ..
        */
        @override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.err.println("在调用真实对象前的服务操作");
            //CGLIB反射调用真实对象方法
            Object result = methodProxy.invokeSuper(proxy, args);
            System.err.println("在调用真实对象hou的服务操作");
            return result;
        }
    
        public void testCglibProxy(){
            CglibProxyExample cpe = new CglibProxyExample();
            ReflectServiceImple1 obj = (ReflectServiceImple1)cpe.getProxy(ReflectServiceImple1.class);
            obj.sayHello("张三");
        }
    }

     本质上是调用了 Enhancer 类,基于父类进行生成代理对象

  • 相关阅读:
    Python GUI编程实例
    Python MySQL事务、引擎、索引及第三方库sqlalchemy
    Python 魔法方法简介
    Python sax模块(SAX解析XML)
    Python minidom模块(DOM写入和解析XML)
    【LOJ】#2432. 「POI2014」代理商 Couriers
    【51nod】1559 车和矩形
    【LOJ】#2430. 「POI2014」沙拉餐厅 Salad Bar
    【LOJ】#2105. 「TJOI2015」概率论
    【BZOJ】1336: [Balkan2002]Alien最小圆覆盖
  • 原文地址:https://www.cnblogs.com/alison-lxj/p/11093616.html
Copyright © 2020-2023  润新知