• java-动态代理


    一、Java自带的动态代理

    1、概述: 

    JDK动态代理主要涉及java.lang.reflect包下的Proxy类和InvocationHandler接口。 JDK代理实现的三个要点:

      通过java.lang.reflect.Proxy类来动态生成代理类
      代理类要实现InvocationHandler接口
      JDK代理只能基于接口进行动态代理

    2、代码结构

                                

    3、Jdk_ProxyService

    package com.turtle.jdk;
    
    public interface Jdk_ProxyService {
    
        public void doUpdate();
    
        public void doSave(String name);
    
        public String doFind();
    
    }

    4、Jdk_ProxyServiceImpl

    package com.turtle.jdk;
    
    /**
     * JDk的动态代理一定要满足实现接口的步骤
     */
    public class Jdk_ProxyServiceImpl implements Jdk_ProxyService {
    
        @Override
        public void doUpdate() {
            System.out.println("进行更新操作");
        }
    
        @Override
        public void doSave(String name) {
            System.out.println("进行保存操作==="+name);
        }
    
        @Override
        public String doFind() {
            System.out.println("进行查询操作");
            return "SUCCESS";
        }
    }

    5、Jdk_MyInvocationHandler

    package com.turtle.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    // 代理类
    public class Jdk_MyInvocationHandler implements InvocationHandler {
    
        // 这个就是我们要代理的真实对象
        private Object target;
        // 构造方法,给我们要代理的真实对象赋初值
        public Jdk_MyInvocationHandler(Object target) {
            this.target = target;
        }
    
        /*
         *invoke方法方法参数解析
         *Object proxy:指被代理的对象。
         *Method method:要调用的方法
         *Object[] args:方法调用时所需要的参数
         *InvocationHandler接口的子类可以看成代理的最终操作类。
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            System.out.println("开始进行代理的增强");
            Object result= null;
            try{
                // 利用反射动态的来反射方法,这就是动态代理和静态代理的区别
                result = method.invoke(target,args);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                System.out.println("代理的增强完毕了");
            }
            return result;
        }
    }

    6、TestJdk

    package com.turtle.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class TestJdk {
        public static void main(String[] args) {
    
            // 我们要代理的真实对象
            Jdk_ProxyService jdkProxyService = new Jdk_ProxyServiceImpl();
            // 我们要代理哪个真实对象,就将该对象传进去
            InvocationHandler invocationHandler = new Jdk_MyInvocationHandler(jdkProxyService);
    
            /*
             *newProxyInstance方法参数解析
             *ClassLoader loader:类加载器
             *Class<?>[] interfaces:得到全部的接口
             *InvocationHandler h:得到InvocationHandler接口的子类实例
             */
            Jdk_ProxyService jdkProxyServiceProxy = (Jdk_ProxyService)Proxy.newProxyInstance(jdkProxyService.getClass().getClassLoader(),jdkProxyService.getClass().getInterfaces(),invocationHandler);
    
            //jdkProxyServiceProxy.doFind();
            // jdkProxyServiceProxy.doSave("测试");
            jdkProxyServiceProxy.doUpdate();
    
        }
    }

    二、使用CgliB来完成动态代理

    1、概述:

            使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

    2、代码结构、Jar包:

                                                                                   

    3、Cglib_ProxyService,被代理对象

    package com.turtle.cglib;
    
    public class Cglib_ProxyService {
    
        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        public final void doDel(){
            System.out.println("正在进行删除操作");
        }
    
        /**
         * 有返回值、无参数
         * @return
         */
        public String doFind(){
            System.out.println("正在进行查询操作");
            return "SUCCESS";
        }
    
        /**
         * 有参数、有返回值
         * @param name
         * @return
         */
        public String doSave(String name){
            System.out.println("正在进行保存操作"+name);
            return "SUCCESS";
        }
    
        /**
         * 无参数、无返回值
         */
        public void doUpdate(){
            System.out.println("正在进行修改操作");
        }
    }

    4、Cglib_MyMethodInterceptor,我们自定义的代理,对对象做增强操作

    package com.turtle.cglib;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * 自己建立的AOP注入
     */
    public class Cglib_MyMethodInterceptor implements MethodInterceptor {
    
        /**
         * @param o cglib生成的代理对象
         * @param method 被代理对象方法
         * @param objects 方法入参
         * @param methodProxy 代理方法
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            String result = null;
            // 通过方法签名来确定我们需要对哪些方法做增强操作
            if(methodProxy.getSignature().getName() == "doUpdate"){
                System.out.println("对doUpdate方法做前置增强");
                methodProxy.invokeSuper(o,objects);
                System.out.println("对doUpdate方法做后置增强");
            }
            if(methodProxy.getSignature().getName() == "doSave"){
                System.out.println("对doSave方法做前置增强");
                methodProxy.invokeSuper(o,objects);
                System.out.println("对doSave方法做后置增强");
            }
            if(methodProxy.getSignature().getName() == "doDel"){
                System.out.println("对doDel方法做前置增强");
                methodProxy.invokeSuper(o,objects);
                System.out.println("对doDel方法做后置增强");
            }
            if(methodProxy.getSignature().getName() == "doFind"){
                System.out.println("对doFind方法做前置增强");
                result = methodProxy.invokeSuper(o,objects).toString();
                System.out.println("对doFind方法做后置增强");
            }
            return result;
        }
    }

    5、Cglib_ProxyFactory,创建一个工厂来实例化我们的代理。

    package com.turtle.cglib;
    
    import net.sf.cglib.proxy.Enhancer;
    
    /**
     * 将用来创建代理对象的操作放到简单工厂里面来实现
     */
    public class Cglib_ProxyFactory<T> {
    
        public T createProxyObj(T obj){
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(obj.getClass());
            // 设置enhancer的回调对象
            enhancer.setCallback(new Cglib_MyMethodInterceptor());
            // 创建代理对象
            return (T)enhancer.create();
        }
    }

    6、TestCglib,测试结果。

    package com.turtle.cglib;
    
    public class TestCglib {
        public static void main(String[] args) {
            // 取得工厂对象
            Cglib_ProxyFactory<Cglib_ProxyService> cglibProxyFactory = new Cglib_ProxyFactory<>();
            // 利用工厂来创建代理对象
            Cglib_ProxyService cglibProxyService = cglibProxyFactory.createProxyObj(new Cglib_ProxyService());
    
            // 通过代理对象调用目标方法
    
            // 无参数、无返回值的方法
            // cglibProxyService.doUpdate();
    
            // 有参数的方法
            // cglibProxyService.doSave("保存");
    
            // 有返回值的方法
            // String result = cglibProxyService.doFind();
            // System.out.println(result);
    
            // 被final修饰的方法
            cglibProxyService.doDel();
        }
    }

    三、总结

  • 相关阅读:
    线程同步——用户模式下线程同步——Slim读写锁实现线程同步
    线程同步——用户模式下线程同步——关键段实现线程同步
    线程同步——用户模式下线程同步——Interlocked实现线程同步
    创建线程
    GDI的 点 线 面 双缓冲 位图的绘制
    简单的windows窗口创建实例
    宽字符与多字符
    学习MFC的建议
    DataGrip 2018.3.1破解激活码
    mysql 主从复制配置
  • 原文地址:https://www.cnblogs.com/zhh19981104/p/11813586.html
Copyright © 2020-2023  润新知