精华内容
下载资源
问答
  • 【Spring基础】CGLIB动态代理实现原理

    万次阅读 多人点赞 2018-06-09 18:11:19
    前言 ... 一 CGLIB介绍 CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库, 它可以在运行期扩展Java类与实现...Hibernate用它来实现PO(Persistent Object 持久化对象)...

    前言

    Github:https://github.com/yihonglei/thinking-in-spring(spring工程)

    一 CGLIB介绍

    CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

    它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

    方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

    除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,

    因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    二 CGLIB动态代理实例

    实现一个业务类,注意,这个业务类并没有实现任何接口:

    package com.jpeony.spring.proxy.cglib;
    
    public class HelloService {
    
        public HelloService() {
            System.out.println("HelloService构造");
        }
    
        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        final public String sayOthers(String name) {
            System.out.println("HelloService:sayOthers>>"+name);
            return null;
        }
    
        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
    }
    

    自定义MethodInterceptor:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * 自定义MethodInterceptor
     */
    public class MyMethodInterceptor implements MethodInterceptor{
    
        /**
         * sub:cglib生成的代理对象
         * method:被代理对象方法
         * objects:方法入参
         * methodProxy: 代理方法
         */
        @Override
        public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("======插入前置通知======");
            Object object = methodProxy.invokeSuper(sub, objects);
            System.out.println("======插入后者通知======");
            return object;
        }
    }

    生成CGLIB代理对象调用目标方法:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
    
    public class Client {
        public static void main(String[] args) {
            // 代理类class文件存入本地磁盘方便我们反编译查看源码
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(HelloService.class);
            // 设置enhancer的回调对象
            enhancer.setCallback(new MyMethodInterceptor());
            // 创建代理对象
            HelloService proxy= (HelloService)enhancer.create();
            // 通过代理对象调用目标方法
            proxy.sayHello();
        }
    }

    运行结果:

    三 CGLIB动态代理源码分析

    实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:

    /*
     * Copyright 2002,2003 The Apache Software Foundation
     *
     *  Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package net.sf.cglib.proxy;
    
    /**
     * General-purpose {@link Enhancer} callback which provides for "around advice".
     * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
     * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
     */
    public interface MethodInterceptor
    extends Callback
    {
        /**
         * All generated proxied methods call this method instead of the original method.
         * The original method may either be invoked by normal reflection using the Method object,
         * or by using the MethodProxy (faster).
         * @param obj "this", the enhanced object
         * @param method intercepted Method
         * @param args argument array; primitive types are wrapped
         * @param proxy used to invoke super (non-intercepted method); may be called
         * as many times as needed
         * @throws Throwable any exception may be thrown; if so, super method will not be invoked
         * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
         * @see MethodProxy
         */    
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
    
    }
    

    这个接口只有一个intercept()方法,这个方法有4个参数:

    1)obj表示增强的对象,即实现这个接口类的一个对象;

    2)method表示要被拦截的方法;

    3)args表示要被拦截方法的参数;

    4)proxy表示要触发父类的方法对象;

    在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:

    /**
         * Generate a new class if necessary and uses the specified
         * callbacks (if any) to create a new object instance.
         * Uses the no-arg constructor of the superclass.
         * @return a new instance
         */
        public Object create() {
            classOnly = false;
            argumentTypes = null;
            return createHelper();
        }

    该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,

    使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:

    private Object createHelper() {
            preValidate();
            Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                    ReflectUtils.getNames(interfaces),
                    filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                    callbackTypes,
                    useFactory,
                    interceptDuringConstruction,
                    serialVersionUID);
            this.currentKey = key;
            Object result = super.create(key);
            return result;
        }

    preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。

    通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法

    创建代理对象的参数。

    protected Object create(Object key) {
            try {
                ClassLoader loader = getClassLoader();
                Map<ClassLoader, ClassLoaderData> cache = CACHE;
                ClassLoaderData data = cache.get(loader);
                if (data == null) {
                    synchronized (AbstractClassGenerator.class) {
                        cache = CACHE;
                        data = cache.get(loader);
                        if (data == null) {
                            Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                            data = new ClassLoaderData(loader);
                            newCache.put(loader, data);
                            CACHE = newCache;
                        }
                    }
                }
                this.key = key;
                Object obj = data.get(this, getUseCache());
                if (obj instanceof Class) {
                    return firstInstance((Class) obj);
                }
                return nextInstance(obj);
            } catch (RuntimeException e) {
                throw e;
            } catch (Error e) {
                throw e;
            } catch (Exception e) {
                throw new CodeGenerationException(e);
            }
        }

    真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

    abstract protected Object nextInstance(Object instance) throws Exception;

    在子类Enhancer中实现,实现源码如下:

    protected Object nextInstance(Object instance) {
            EnhancerFactoryData data = (EnhancerFactoryData) instance;
    
            if (classOnly) {
                return data.generatedClass;
            }
    
            Class[] argumentTypes = this.argumentTypes;
            Object[] arguments = this.arguments;
            if (argumentTypes == null) {
                argumentTypes = Constants.EMPTY_CLASS_ARRAY;
                arguments = null;
            }
            return data.newInstance(argumentTypes, arguments, callbacks);
        }

    看看data.newInstance(argumentTypes, arguments, callbacks)方法,

    第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

    最后根据这些参数,通过反射生成代理对象,源码如下:

    /**
             * Creates proxy instance for given argument types, and assigns the callbacks.
             * Ideally, for each proxy class, just one set of argument types should be used,
             * otherwise it would have to spend time on constructor lookup.
             * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
             * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
             *
             * @see #createUsingReflection(Class)
             * @param argumentTypes constructor argument types
             * @param arguments constructor arguments
             * @param callbacks callbacks to set for the new instance
             * @return newly created proxy
             */
            public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
                setThreadCallbacks(callbacks);
                try {
                    // Explicit reference equality is added here just in case Arrays.equals does not have one
                    if (primaryConstructorArgTypes == argumentTypes ||
                            Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
                        // If we have relevant Constructor instance at hand, just call it
                        // This skips "get constructors" machinery
                        return ReflectUtils.newInstance(primaryConstructor, arguments);
                    }
                    // Take a slow path if observing unexpected argument types
                    return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
                } finally {
                    // clear thread callbacks to allow them to be gc'd
                    setThreadCallbacks(null);
                }
    
            }

    最后生成代理对象:

    将其反编译后代码如下:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.jpeony.spring.proxy.cglib;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.core.ReflectUtils;
    import net.sf.cglib.core.Signature;
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.Factory;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class HelloService$$EnhancerByCGLIB$$be45efdd extends HelloService implements Factory {
        private boolean CGLIB$BOUND;
        public static Object CGLIB$FACTORY_DATA;
        private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
        private static final Callback[] CGLIB$STATIC_CALLBACKS;
        private MethodInterceptor CGLIB$CALLBACK_0;
        private static Object CGLIB$CALLBACK_FILTER;
        private static final Method CGLIB$sayHello$0$Method;
        private static final MethodProxy CGLIB$sayHello$0$Proxy;
        private static final Object[] CGLIB$emptyArgs;
        private static final Method CGLIB$equals$1$Method;
        private static final MethodProxy CGLIB$equals$1$Proxy;
        private static final Method CGLIB$toString$2$Method;
        private static final MethodProxy CGLIB$toString$2$Proxy;
        private static final Method CGLIB$hashCode$3$Method;
        private static final MethodProxy CGLIB$hashCode$3$Proxy;
        private static final Method CGLIB$clone$4$Method;
        private static final MethodProxy CGLIB$clone$4$Proxy;
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$be45efdd");
            Class var1;
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
            CGLIB$equals$1$Method = var10000[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = var10000[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = var10000[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = var10000[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
            CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService")).getDeclaredMethods())[0];
            CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
        }
    
        final void CGLIB$sayHello$0() {
            super.sayHello();
        }
    
        public final void sayHello() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
            } else {
                super.sayHello();
            }
        }
    
        final boolean CGLIB$equals$1(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$2() {
            return super.toString();
        }
    
        public final String toString() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
        }
    
        final int CGLIB$hashCode$3() {
            return super.hashCode();
        }
    
        public final int hashCode() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
                return var1 == null ? 0 : ((Number)var1).intValue();
            } else {
                return super.hashCode();
            }
        }
    
        final Object CGLIB$clone$4() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$4$Proxy;
                }
                break;
            case 1535311470:
                if (var10000.equals("sayHello()V")) {
                    return CGLIB$sayHello$0$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$1$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$2$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$3$Proxy;
                }
            }
    
            return null;
        }
    
        public HelloService$$EnhancerByCGLIB$$be45efdd() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
            CGLIB$THREAD_CALLBACKS.set(var0);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
            CGLIB$STATIC_CALLBACKS = var0;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object var0) {
            HelloService$$EnhancerByCGLIB$$be45efdd var1 = (HelloService$$EnhancerByCGLIB$$be45efdd)var0;
            if (!var1.CGLIB$BOUND) {
                var1.CGLIB$BOUND = true;
                Object var10000 = CGLIB$THREAD_CALLBACKS.get();
                if (var10000 == null) {
                    var10000 = CGLIB$STATIC_CALLBACKS;
                    if (var10000 == null) {
                        return;
                    }
                }
    
                var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
            }
    
        }
    
        public Object newInstance(Callback[] var1) {
            CGLIB$SET_THREAD_CALLBACKS(var1);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd;
            switch(var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
        public Callback getCallback(int var1) {
            CGLIB$BIND_CALLBACKS(this);
            MethodInterceptor var10000;
            switch(var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
            }
    
            return var10000;
        }
    
        public void setCallback(int var1, Callback var2) {
            switch(var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
            }
        }
    
        public Callback[] getCallbacks() {
            CGLIB$BIND_CALLBACKS(this);
            return new Callback[]{this.CGLIB$CALLBACK_0};
        }
    
        public void setCallbacks(Callback[] var1) {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        }
    
        static {
            CGLIB$STATICHOOK1();
        }
    }
    

    重点关注代理对象的sayHello方法:

    从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,

    intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中

    的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

    JDK动态代理实现原理(jdk8)

     

    展开全文
  • JDK和CGLib动态代理实现和区别

    千次阅读 2019-12-02 16:38:25
    JDK和CGLib动态代理实现 动态代理在Java中有着广泛的应用,如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等。动态代理的代理关系是在运行时期确定的。在讲解两种动态代理区别之前,...

    前言

    上周五在电面试阿里时,被问到Spring AOP中JDK和CGLib动态代理的区别?于是搜集网上相关知识点,在此整理一下,供大家参考。

    JDK和CGLib动态代理实现

    动态代理在Java中有着广泛的应用,如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等。动态代理的代理关系是在运行时期确定的。在讲解两种动态代理区别之前,首先通过实例代码分别实现两种动态代理,直观感受一下动态代理是个什么东西,是如何实现的,然后通过分析其实现方式和原理,阐述两种动态代理的区别。

    Jdk原生动态代理

    IHelloService接口

    public interface IHelloService {
        void sayHello();
    }

    HelloServiceImpl实现类

    public class HelloServiceImpl implements IHelloService {
        @Override
        public void sayHello() {
            System.out.println("Jdk say Hello");
        }
    }

    JdkDynamicProxy实现InvocationHandler接口类

    public class JdkDynamicProxy implements InvocationHandler {
    
        private Object targetObject;
    
        public Object newProxyInstance(Object targetObject) {
            //将目标对象传入进行代理
            this.targetObject = targetObject;
            //返回代理对象
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxyObject, Method method, Object[] args) throws Throwable {
            System.out.println("JdkDynamicProxy," + method.getName() + "方法,执行之前");
            return method.invoke(this.targetObject, args);
        }
    }

    在该类除了覆写invoke()方法,还封装了一个生成代理类的方法,该方法可以不放置在此的。上述代码的关键是Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) 方法,该方法会根据指定的参数动态创建代理对象。三个参数的意义如下:

    1. loader,指定代理对象的类加载器;
    2. interfaces,代理对象需要实现的接口,可以同时指定多个接口;
    3. handler,方法调用的实际处理者,代理对象的方法调用都会转发到这里(*注意1)。

    newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法。动态代理神奇的地方就是:

    1. 代理对象是在程序运行时产生的,而不是编译期;
    2. 对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等。

    注意1:对于从Object中继承的方法,JDK Proxy会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发。详见JDK Proxy官方文档

    测试代码:

    @Test
    public void jdkDynamicProxyPatternTest() {
        IHelloService helloService = new HelloServiceImpl();
        IHelloService proxySubject = (IHelloService) new JdkDynamicProxy2().newProxyInstance(helloService);
        proxySubject.sayHello();
    }

    运行结果:

    image.png

    JDK动态代理整个实现过程其实很简单,包括三个步骤:

    1. 定义一个接口IHelloService,大家都知道Jdk的动态代理是基于接口,这个就是那个接口。
    2. 编写一个实现该接口的类HelloServiceImpl,这个就是目标对象,也就是被代理的对象类。
    3. 最后编写一个实现InvocationHandler接口的类JdkDynamicProxy,代理类的方法调用都会被转发到该类的invoke()方法。

     

    CGLib动态代理

    HelloService没有实现任何接口的类

    public class HelloService {
        public void sayHello() {
            System.out.println("Cglib Say Hello");
        }
    }

    CglibDynamicProxy实现MethodInterceptor接口类

    public class CglibDynamicProxy implements MethodInterceptor {
    
        // 维护目标对象
        private Object target;
    
        public CglibDynamicProxy(Object target) {
            this.target = target;
        }
    
        //给目标对象创建一个代理对象
        public Object newProxyInstance(){
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(target.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.创建子类(代理对象)
            return en.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("CglibDynamicProxy,"+ method.getName()+"方法,执行之前");
            Object returnValue = method.invoke(target, args);
            System.out.println("CglibDynamicProxy,"+ method.getName()+"方法,执行之后");
            return returnValue;
        }
    }

    上述代码中,通过CGLIB的Enhancer来指定要代理的目标对象(target.getClass())、实际处理代理逻辑的对象(this),最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等。CGLIG中MethodInterceptor的作用跟JDK代理中的InvocationHandler很类似,都是方法调用的中转站。

    注意:对于从Object中继承的方法,CGLIB代理也会进行代理,如hashCode()equals()toString()等,但是getClass()wait()等方法不会,因为它是final方法,CGLIB无法代理。

     

    测试代码:

    @Test
    public void cglibDynamicProxyPatternTest() {
        HelloService cglibProxySubject = (HelloService) new CglibDynamicProxy(new HelloService()).newProxyInstance();
        cglibProxySubject.sayHello();
    }

    运行结果:

    image.png

     

    JDK和CGLib动态代理分析

    自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方。JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑(如:我们在方法执行前后打印的日志,本文只是为了演示,实际的应用一般不会只是简单的打印日志的),并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。

     

    JDK动态代理的话,他有一个限制,就是它只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是CGLib。


    CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。

     

    JDK和CGLib动态代理区别

    1、JDK动态代理具体实现原理:

    • 通过实现InvocationHandler接口创建自己的调用处理器;
    • 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
    • 通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
    • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

    JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

    2、CGLib动态代理:

    利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    3、两者对比:

    • JDK动态代理是面向接口的。
    • CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败。

    4、使用注意:

    • 如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);
    • 如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

     

    JDK和CGLib动态代理性能对比

    关于两者之间的性能的话,网上有人对于不通版本的jdk进行测试,经过多次试验,测试结果大致是这样的,在1.6和1.7的时候,JDK动态代理的速度要比CGLib动态代理的速度要慢,但是并没有教科书上的10倍差距,在JDK1.8的时候,JDK动态代理的速度已经比CGLib动态代理的速度快很多了,但是JDK动态代理和CGLIB动态代理的适用场景还是不一样的哈!

     

    最后希望小伙伴在遇到这个问题的时候能够有的放矢!稍微把问题拓展一下,不要是说两者的区别,应该循序渐进,娓娓道来。

     

     

    参考文章:
    https://www.cnblogs.com/CarpenterLee/p/8241042.html

    https://blog.csdn.net/yhl_jxy/article/details/80635012

    展开全文
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解动态代理原理,对学习AOP框架至关重要。 JDK动态代理不需要任何外部依赖,但是只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有...

    什么是代理模式

    举个栗子,比如兰蔻想找安妮海瑟薇代言香水广告,假设兰蔻方代表为Jack,那么是不是Jack直接闯到Anne豪宅扯一嗓子“Anne 妹纸,我这有个私活你接不接”;实际情况肯定不是这样,且不说这个操作太鲁莽(搞不好还会被一枪崩掉),合作本身涉及的事项就很多,比如有木有档期,出场费怎么定价,要买哪些保险,税费怎么处理,违约责任等等,显然这里面财务、保险、法律相关的问题Anne一个人肯定搞不定,需要专业人士处理;而这所有的一切都可以交给Anne的经纪人(或者团队)Team来协办,作为一个艺人Anne只管拍广告就可以了。

    在这个场景中,Jack是客户(代表兰蔻集团),Anne是艺人提供代言服务直接参与广告拍摄,Team是代理(帮Anne处理商务事宜),所有合作细节都是Jack找Team商谈完成,找Team谈合作一样能达成目标(拍代言广告),而且比直接找Anne本人效率更高,更稳妥。

    静态代理

    若代理类在程序运行前就已经存在,这种方式称为静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的(hard coding)。 通常情况下, 静态代理中的代理类和目标类(委托l类)会实现同一接口或是派生自相同的父类。
    在这里插入图片描述
    此例中,Atm是被代理的目标对象(委托对象),Crs持有Atm的引用,是代理对象,调用Crs的withdraw方法实际被转到Atm的withdraw

    public interface Account {/*目标类与代理类都实现该接口*/
    	String withdraw(double amount);
    }
    
    public class Atm implements Account{/*自动取款机,目标类(被代理)*/
    	@Override
    	public String withdraw(double amount) {
    		return "取出"+ amount +"元";
    	}
    }
    
    public class Crs implements Account {/*自动存取款机,此处为Atm的代理类*/
    
    	private Account account = new Atm();/*持有被代理对象的引用,静态代理*/
    	@Override
    	public String withdraw(double amount) {
    		return account.withdraw(amount);/*取款调用的是目标对象的方法*/
    	}
    	
    	public String deposit() {/*代理类可以有自己的业务操作*/
    		return "存款120元";
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Crs crs = new Crs();/*创建代理对象*/
    		System.out.println(crs.withdraw(100));
    	}
    }
    

    静态代理的不足

    静态代理实现简单容易理解,但是静态代理不能使一个代理类反复作用于多个不同的目标对象,代理对象直接持有目标对象的引用,导致代理对象和目标对象的耦合。如果Account接口还有另一个实现类也需要进行事务控制,那么就要定义一个新的代理类,这样就会产生许多重复的模版代码,代码复用率不高。而动态代理就可以很好的解决这类问题。

    JDK动态代理

    静态代理的代理关系在编译时确定,而动态代理的代理关系在运行时确定,动态代理更灵活。

    JDK动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的

    目标与代理的共同接口

    public interface Account {/*目标类与代理类都实现该接口,接口定义业务操作*/
    	String withdraw(double amount);
    }
    

    目标对象

    public class Atm implements Account{/*自动取款机,目标类*/
    	@Override
    	public String withdraw(double amount) {
    		return "取出"+ amount +"元";
    	}
    }
    

    handler

    //InvocationHandler,对代理类方法的调用会被转到该类的invoke()方法。
    public class AtmInvocationHandler implements InvocationHandler {
    	private Object target;
    	
    	public AtmInvocationHandler(Object target) {/*绑定对象*/
    		this.target = target;
    	}
    
    	public Object getProxy() {
    		/* 获取代理对象
    		
    		参数说明:
    		loader,指定代理对象的类加载器;
    		interfaces,代理对象需要实现的接口数组;
    		handler,方法调用的实际处理者
    
    		newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法。
    		*/
    		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    				target.getClass().getInterfaces(), this); // 需要绑定接口
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		Object result = null;
    		System.out.println("取款操作");
    		result = method.invoke(target, args);
    		System.out.println(result);
    		System.out.println("取款完成");
    		return result;
    	}
    
    }
    
    public class Test {
    	public static void main(String[] args){
    		AtmInvocationHandler handler = new AtmInvocationHandler(new Atm());
    		Object atmProxy = handler.getProxy();
    		Account accout = (Account)atmProxy;
    		Object result = accout.withdraw(100.0);
    	}
    }
    
    取款操作
    取出100.0元
    取款完成
    

    JDK动态代理小结

    代理类AtmInvocationHandler实现了InvocationHandler接口,与静态代理不同它持有的目标对象类型是Object,因此代理类AtmInvocationHandler能够代理任意的目标对象,给目标对象添加事务控制的逻辑。因此动态代理真正实现了将代码中横向切面逻辑的剥离,实现了代码复用。

    JDK动态代理的缺点:
    (一)通过反射类Proxy和InvocationHandler回调接口实现JDK动态代理,要求目标类必须实现一个接口,对于没有实现接口的类,无法通过这种方式实现动态代理。
    (二)动态代理会为接口中的声明的所有方法添加上相同的代理逻辑,不够灵活

    CGLIB动态代理

    CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB支持接口、继承方式实现代理。

    \color{blue}{原理}:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势将横切逻辑织入(weave)目标对象

    CGLIB代理实现步骤:

    1、定义目标对象

    public class Atm{/*自动取款机,目标类,不需要实现指定接口*/
    	public String withdraw(double amount) {
    		return "取出"+ amount +"元";
    	}
    	
    	public String checkBalance() {
    		return "当前余额:" + 1200 + "元";
    	}
    }
    

    2、定义拦截器。在调用目标对象的方法时,CGLib会回调MethodInterceptor接口的intercept方法实施拦截,来切入代理逻辑,类似于JDK中的InvocationHandler接口

    public class AtmInterceptor implements MethodInterceptor {
    	/**
         * obj:cglib生成的代理对象
         * method:被代理对象方法
         * args:方法入参
         * methodProxy: 代理方法
        */	
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    		System.out.println("事务开始");
    		Object result = proxy.invokeSuper(obj, args);
    		System.out.println(result);
    		System.out.println("事务结束");
    		return result;
    	}
    }
    

    3、在需要使用目标对象的时候,通过CGLIB动态代理获取代理对象。

    public class Test {
    	public static void main(String[] args) {
    		//class 文件缓存目录,如果不研究动态类的源码可以不设置
    		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\cglib_classes");	
    		//用于创建代理对象的增强器,可以对目标对象进行扩展
    		Enhancer enhancer = new Enhancer();
    		//将目标对象设置为父类
    		enhancer.setSuperclass(Atm.class);
    		//设置目标拦截器
    		enhancer.setCallback(new AtmInterceptor());
    		// 创建代理对象
    		Atm atm = (Atm)enhancer.create();
    		// 通过代理对象调用目标方法
    		Object result = atm.withdraw(100);
    		atm.checkBalance();
    	}
    }
    

    目标对象的每个方法调用都会被拦截

    CGLIB debugging enabled, writing to 'D:\cglib_classes'
    事务开始
    取出100.0元
    事务结束
    事务开始
    当前余额:1200元
    事务结束
    

    以上代码通过CGLIB的Enhancer指定要代理的目标对象(即包含实际业务逻辑的对象),再通过调用create()方法得到代理对象,所有对代理对象的非final方法的调用都会指派给AtmInterceptor.intercept()方法,在intercept()方法中可以加入目标对象之外的业务逻辑,比如参数校验、日志审计、安全检查等功能;通过调用MethodProxy.invokeSuper()方法,将调用转发给原始对象,也就是本例的Atm 。CGLIG中MethodInterceptor的作用与JDK代理中的InvocationHandler类似,都是方法调用的中转派发。

    两种动态代理方式的比较

    JDK动态代理不需要任何外部依赖,但是只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法代理final对象与final方法。(final类型不能有子类,final方法不能被重载)

    动态代理是 AOP(Aspect Orient Programming)编程思想,理解动态代理原理,对学习AOP框架至关重要。

    展开全文
  • SpringJDK动态代理实现

    千次阅读 2021-01-17 22:18:01
    目录JDK动态代理代码实现 JDK动态代理 JDK动态代理使用Proxy类里面的newProxyInstance方法创建代理对象。 Modifier and Type Method and Description static Object newProxyInstance(ClassLoader loader, ...

    JDK动态代理

    JDK动态代理使用Proxy类里面的newProxyInstance方法创建代理对象。

    Modifier and Type Method and Description
    static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。

    方法里有三个参数:
    第一个参数:类加载器。
    第二个参数:增强方法所在类,这个类实现的接口,支持多个接口。
    第三个参数:实现这个接口InvocationHandler创建代理的对象,在这个类里写增强的方法。

    代码实现

    (1)创建接口,定义方法。
    (2)创建接口实现类,实现方法。
    (3)使用Proxy类创建接口代理对象。

    UserDao接口:

    package com.Keafmd.spring5;
    
    /**
     * Keafmd
     *
     * @ClassName: UserDao
     * @Description:
     * @author: 牛哄哄的柯南
     * @date: 2021-01-17 20:41
     */
    
    public interface UserDao {
    
        public int add(int a,int b);
    
        public String updat(String id);
    }
    

    UserDaoImpl实现类:

    package com.Keafmd.spring5;
    
    /**
     * Keafmd
     *
     * @ClassName: UserDaoImpl
     * @Description: 实现类
     * @author: 牛哄哄的柯南
     * @date: 2021-01-17 20:42
     */
    public class UserDaoImpl implements UserDao{
        @Override
        public int add(int a, int b) {
            System.out.println("add执行中...");
            return a+b;
        }
    
        @Override
        public String updat(String id) {
            System.out.println("updat执行中...");
            return id;
    
        }
    }
    

    JDKProxy类:

    package com.Keafmd.spring5;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * Keafmd
     *
     * @ClassName: JDKProxy
     * @Description:
     * @author: 牛哄哄的柯南
     * @date: 2021-01-17 20:44
     */
    public class JDKProxy {
        public static void main(String[] args) {
            //创建接口实现类代理对象
            Class[] interfaces = {UserDao.class};
            
            /*Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return null;
                }
            });*/
    
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
    
            System.out.println("-----------对add方法进行增强----------");
            int result = dao.add(1, 2);
            System.out.println("result:" + result);
    
            System.out.println("------------不增强updat方法------------");
    
            String res = dao.updat("Keafmd");
            System.out.println("res:" + res);
    
        }
    }
    
    //创建代理对象代码
    class UserDaoProxy implements InvocationHandler {
    
        //把创建的是谁的代理对象,把谁传递过来
        //有参构造传递
        private Object obj;
    
        public UserDaoProxy(Object obj) {
            this.obj = obj;
        }
    
        //增强的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            if ("add".equals(method.getName())) { //通过判断实现对不同方法的增强
    
    
                //方法执行之前
                System.out.println("方法之前执行..." + method.getName());
    
                //被增强的方法执行
                Object res = method.invoke(obj, args);
    
                //方法执行之后
                System.out.println("方法之后执行" + obj);
    
                return res;
    
            } else { //不增强
    
                Object res = method.invoke(obj, args);
                return res;
    
            }
        }
    }
    

    输出结果:

    -----------对add方法进行增强----------
    方法之前执行...add
    add执行中...
    方法之后执行com.Keafmd.spring5.UserDaoImpl@5e481248
    result:3
    ------------不增强updat方法------------
    updat执行中...
    res:Keafmd
    
    Process finished with exit code 0
    

    以上就是JDK动态代理的代码实现,在Spring5里面已经把动态代理的代码已经做了封装。

    看完如果对你有帮助,感谢点赞支持!
    如果你是电脑端的话,看到右下角的 “一键三连” 了吗,没错点它[哈哈]

    在这里插入图片描述

    加油!

    共同努力!

    Keafmd

    展开全文
  • cglib动态代理实现原理详细分析

    千次阅读 2019-01-01 18:29:08
    在上篇JDK动态代理实现原理详细分析中,对其JDK代理的流程做了一个详细的分析。而本文,将介绍另一种动态代理模式:cglib动态代理。阅读完本文,你将对cglib代理模式的运行的流程有一个清晰的认识。 本文的目录如下:...
  • 动态代理实现的三种方式

    千次阅读 2017-06-22 13:18:05
    动态代理实现有三种方式,jdk动态代理(基于接口),cglib动态代理(基于继承),javassist(hibernate中使用这种方式)实现动态代理一 jdk实现动态代理package com.lzzl.jdkproxy;public interface Pet { public ...
  • Java动态代理实现

    千次阅读 2018-12-05 16:42:07
    在java的动态代理机制中,有两个重要的类和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。 下面先贴上代码: 首先需要一个接口: /* *...
  • 模拟JDK动态代理实现

    千次阅读 2016-06-01 19:46:37
    在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理实现AOP的绝好底层技术。 JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个...
  • Javassist的动态代理实现

    千次阅读 2016-07-02 12:00:11
    AOP - 面向切面编程 - 就是基于动态代理实现的。 为什么要提代理模式。因为AOP的广泛实现都是通过动态代理,而动态代理又不得不说代理模式。 代理模式,顾名思义,就是对一个类的访问,变为访问这个类的代理人。...
  • Android 动态代理以及利用动态代理实现 ServiceHook

    万次阅读 多人点赞 2017-02-25 20:44:15
    Android 利用 ServiceHook 实现特殊功能
  • Java动态代理实现接口方法

    千次阅读 2015-03-30 11:50:53
    最近正在看Mybatis源码,重点研究了自定义Mapper接口里方法实现如何与xml配置文件进行绑定,最后了解到是通过java动态代理实现了接口方法。 主要使用了Proxy.newProxyInstance(loader, interfaces, ...
  • 摘要:本文主要讲了Spring Aop动态代理实现的两种方式。 1. Spring AOP Spring是一个轻型容器,Spring整个系列的最最核心的概念当属IoC、AOP。可见AOP是Spring框架中的核心之一,在应用中具有非常重要的作用,也是...
  • 有接口的CGLIB动态代理实现

    千次阅读 2017-03-31 17:05:00
    有接口的CGLIB动态代理实现定义接口package com.hk.service; /** * 定义一个接口(一类人要做的事情) * @author 浪丶荡 * */ public interface ISomeService { //打官司 public String Litigate(); //吃饭 ...
  • Cglib动态代理实现解析

    千次阅读 2018-04-11 23:05:14
    在 JDK 动态代理源码解读 已经知道了JDK 动态代理实现逻辑,这里我们来学习一下Cglib 的实现逻辑。以方便对动态代理有一个全面的认识。 首先,我们来看一下生成代理类的时序图,对比起JDK的实现,它复杂了很多。 ...
  • java动态代理实现

    千次阅读 2019-01-15 14:42:46
    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。  一、代理模式  代理模式是常用的java设计模式,他的特征是...
  • 细说Spring——AOP详解(动态代理实现AOP)

    千次阅读 多人点赞 2018-06-05 21:25:11
    前言 嗯,我应该是有一段实现没有写...决定还是要克服困难,我仔细的想了一下怎么讲解AOP实现这一部分,然后我决定由浅入深的讲解动态代理,然后用动态代理实现一个简单的AOP,感觉这样能够让人对AOP的原理有一个比...
  • Mybatis源码中Mapper的动态代理实现原理现在工作中用的最多的就是Mybatis这款半自动ORM框架,用的久却对其了解不是很深,现在准备对其进行一些深入的学习,顺便对知识进行查漏补缺.本篇是对Mapper动态代理原理的详解....
  • 动态代理实现AOP

    千次阅读 热门讨论 2017-10-14 21:32:29
    今天说和小张哥一起讨论AOP,正好看到了相关的视频,今天就总结一下AOP是如何使用动态代理实现的。AOP对JAVA程序员来说并不陌生,他是spring的一个核心内容——面向切面编程,先把概念放在这里,因为这一篇博客...
  • java动态代理实现接口调用

    千次阅读 2019-10-14 11:17:33
    动态代理是基于接口实现的代理,mybatis就是用这个技术实现的 首先,创建一个最基本接口和实现类: interface UserManager { void addUser(); } class UserManagerImpl implements UserManager{ @Override ...
  • java 动态代理实现原理

    千次阅读 2015-07-10 21:08:26
    上篇讲了:java动态代理浅析 这篇讲讲其内部实现原理。 1、相关的类和接口 1.1 java.lang.reflect.Proxy 这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。 Proxy 的...
  • 【Spring基础】JDK动态代理实现原理(jdk8)

    万次阅读 多人点赞 2018-06-05 21:32:47
    前言 Github:... 一 JDK动态代理 在了解JDK动态代理前,有需要可以了解下代理模式。 ...天天的都听到人们说JDK动态代理,听上去感觉好屌的样子,为什么要叫JDK动态代理? ...
  • 我们知道MyBatis通过动态代理的方式,实现了只通过Mapper接口而无接口的实现类的方式操作数据库。 熟悉源码的同学应该知道如下代码(MapperProxy.invoke()): ``` @Override public Object invoke...
  • C#动态代理实现AOP

    千次阅读 2018-04-15 11:55:07
    C#实现动态aop比较麻烦,需要用到IL中间语言的知识,笔者最近也在研究,在这... /// 创建动态代理方法 /// &lt;/summary&gt; /// &lt;param name="typeBuilder"&gt;类型构造器&lt;...
  • 一、代理在使用动态代理实现拦截器之前我们先简单了解一下什么Java的代理。代理,顾名思义,就是不直接操作被代理(下面都用目标对象称呼,听起来舒服一些)对象,而是通过一个代理对象去间接的使用目标对象中的方法...
  • java动态代理实现与原理详细分析

    千次阅读 多人点赞 2019-02-08 23:22:43
    一、代理 (1)、什么是代理? 大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户----&gt;...
  • Spring动态代理实现

    千次阅读 2013-07-31 20:36:17
    第一次写自己的技术博客,希望这点东西能够帮助到一些人,同时有什么不对的地方请大家多多指教。...JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandl
  • 深入剖析JDK动态代理实现原理

    千次阅读 2018-01-21 17:35:20
    比如说有一个业务需要我们在添加或者删除用户的时候,将信息添加到日志当中,但是把日志的代码插入原有的业务代码中是很不雅观的,为了不破坏原有的实现类,这时候我们就可以用到动态代理。 接口类 public ...
  • 使用Java动态代理实现的拦截器

    千次阅读 2013-08-12 22:38:16
    声明:本文中通过Java的动态代理实现的拦截器只是能够在目标方法执行之前、之后调用拦截器方法,属于比较初级的应用。  在软件开发领域,有一条很重要的规则:Don’t Repeat Yourself,即DRY规则,意思是不要书写...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 357,649
精华内容 143,059
关键字:

动态代理怎么实现