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

    动态代理模式示意图

    要实现动态代理分为两个步骤:

    • 代理对象和真实对象建立代理关系
    • 实现代理对象的代理逻辑方法

    在Java中有多种动态代理技术, 例如: JDK , CGLIB , Javassist , ASM, 其中最常用的动态代理技术有两种:一种是JDK动态代理, 这是JDK自带的功能,; 另一种是CGLIB,这是第三方提供的一个技术, 目前Spring常用JDK和CGLIB, 而MyBatis使用了Javassist, 无论哪种代理技术, 它们的力量都是相似的.

    1. JDK动态代理

     JDK动态代理是java.lang.reflect.* 包提供的方式, 它必须借助一个接口才能实现动态代理

    public interface StudentService {
        void sayHello();
    }
    
    public class StudentServiceImpl implements StudentService{
    
        @Override
        public void sayHello() {
            System.out.println("Student sayHello.....");
        }
    }
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    /**
     * 使用JDK实现代理对象模式
     */
    public class JdkProxyExample implements InvocationHandler {
    
        //真实对象
        private Object target = null;
    
        /**
         * 建立代理对象和真实对象的代理关系,并返回代理对象
         * @param target 真实对象
         * @return 代理对象
         */
        public Object bind(Object target){
            this.target = target;
         //第1个参数:类加载器, 第二个参数:把生成动态代理对象挂在哪些接口下, 第3个参数:实现方法逻辑的代理类的对象
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } /** * * @param proxy 代理对象 * @param method 当前调用的方法 * @param args 当前方法的参数 * @return 代理结果返回 * @throws Throwable 异常 */ @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; } }

    测试JDK代理

    public class JdkProxyDemo {
        public static void main(String[] args) {
            
            JdkProxyExample example = new JdkProxyExample();
            //获取当前对象的代理对象
            StudentService proxy = (StudentService) example.bind(new StudentServiceImpl());
            proxy.sayHello();
        }
    }

     结果:

    2. CGLIB动态代理

    JDK动态代理必须提供接口才能使用, 在一些不能提供接口的环境中, 只能采用其他第三方技术, 比如CGLIB动态代理. 它的优势在不需要提供接口, 只要一个非抽象类就能实现动态代理.

    public class StudentServiceImpl {
        public void sayHello(){
            System.out.println("Student sayHello");
        }
    }
    
    /**
     * cglib实现动态代理
     */
    public class CglibProxyExample implements MethodInterceptor {
    
        /**
         * 生成CGLIB代理对象
         * @param cls Class类
         * @return Class类的CGLIB代理对象
         */
        public Object getProxy(Class cls){
            //CGLIB enhancer增强类对象
            Enhancer enhancer = new Enhancer();
            //设置增强类型
            enhancer.setSuperclass(cls);
            //定义代理逻辑对象为当前对象,要求当前对俩实现MethodInterceptor
            enhancer.setCallback(this);
            //生成并返回代理对象
            return enhancer.create();
        }
    
        /**
         * 代理逻辑方法
         * @param proxy 代理对象
         * @param method 方法
         * @param args 方法参数
         * @param methodProxy 方法代理
         * @return 代理逻辑返回
         * @throws Throwable 异常
         */
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
            System.out.println("调用真实对象前.....");
    
            //GBLIB反射调用真实对象方法
            Object result = methodProxy.invokeSuper(proxy, args);
    
            System.out.println("调用真实对象后.....");
            return result;
        }
    }
    
    public class CglibDemo {
        public static void main(String[] args) {
            CglibProxyExample example = new CglibProxyExample();
            StudentServiceImpl obj = (StudentServiceImpl) example.getProxy(StudentServiceImpl.class);
            obj.sayHello();
        }
    }

     CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理

  • 相关阅读:
    CSS3 颜色渐变、阴影、渐变的阴影
    AxureRP分页签 / Tab选项卡切换功能~
    这是我的第一篇博客!
    天池nlp新人赛_task6
    天池nlp新人赛_task5
    天池nlp新人赛_task4
    天池nlp新人赛_task3.对TF-IDF进一步认识
    天池nlp新人赛_task2:数据预处理改进和一些思路
    天池nlp新人赛_task1
    希尔伯特空间
  • 原文地址:https://www.cnblogs.com/guo-rong/p/9694404.html
Copyright © 2011-2022 走看看