JDK动态代理 vs CGLib动态代理

Spring 动态代理机制

Spirng的AOP的动态代理实现机制有两种,分别是:

1)JDK动态代理:

具体实现原理:

1、通过实现InvocationHandlet接口创建自己的调用处理器

2、通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理

3、通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型

4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,

Spring通过java的反射机制生成被代理接口的新的匿名实现类,重写了其中AOP的增强方法。


2、CGLib动态代理

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。


两者对比:

JDK动态代理是面向接口,在创建代理实现类时比CGLib要快,创建代理速度快。

CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败),在创建代理这一块没有JDK动态代理快,但是运行速度比JDK动态代理要快。

使用注意:

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

如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

那么如何选择的使用代理机制了?

通过配置Spring的中<aop:config>标签来显示的指定使用动态代理机制 proxy-target-class=true表示使用CGLib代理,如果为false就是默认使用JDK动态代理


--------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------

Jdk动态代理是装饰模式的一个典型用例,关于装饰模式这里不多解释,直接说重点吧.jdk动态代理实际上就是代替继承方案,在不破坏原始类的原则下,在运行期间为某个类动态注入一些新的方法。java.lang.reflect.Proxy提供了生成代理类的接口。进入源代码,我们可以看见关于Proxy的详细说明这里截取一些关键的部分:

复制代码

/**
 * {@code Proxy} provides static methods for creating dynamic proxy
 * classes and instances, and it is also the superclass of all
 * dynamic proxy classes created by those methods.
 *(Proxy提供了提供了一系列生成动态代理类或实例静态的方法,它是所有动态代理类的超类)
 *    目标类:就是你要代理的对象
 *    代理类:代理目标类执行动作的类
 *
 * <p>To create a proxy for some interface {@code Foo}:
 *(给目标类添加一些方法(接口)生成代理类的方法:)
 * <pre>
 *    //获取自定义处理类对象
 *     InvocationHandler handler = new MyInvocationHandler(...);
 *    //获取代理类字节码对象
 *     Class&lt;?&gt; proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
 *    //生成代理类对象实例
 *     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
 *                     newInstance(handler);
 * </pre>
 * or more simply:(也可以用如下更简单的方式:)
 * <pre>
 *    //这里使用了匿名内部类的方式,直接将处理逻辑推迟到用户具体定义使用的时候,具有极大的灵活性
 *    
 *    //Foo.class.getClassLoader()获取类加载器,以便将代理类注册到内存,实际上这里是指虚拟机
 *      //new Class<?>[] { Foo.class } 获取目标类所有的方法(接口)
 *    //handler 自定义的处理逻辑,也就是说你拿到方法后要干什么
 * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
 *                                          new Class&lt;?&gt;[] { Foo.class },
 *                                          handler);
 * </pre>

复制代码

官方已经详细介绍了这个接口的使用方法,同时也对其中的原理做了阐述,这里就直接上实例来说说具体用法吧,jdk动态代理的实现原理 这种鬼东西至少也要在你会用的基础上再研究吧,等你会用了,自

己直接看源码去,以你的智商那还不是小ks。

  • 目标类接口设计 
  • 复制代码

    package com.heima_aop;
    
    public interface UserService {
        public void addUser();
        public void updateUser();
        public void deleteUser();
    }

    复制代码

  • 目标类接口实现
  • 复制代码

    package com.heima_aop;
    
    public class UserServiceImpl implements UserService {
    
        @Override
        public void addUser() {
            System.out.println("addUser");
        }
    
        @Override
        public void updateUser() {
            System.out.println("updateUser");
        }
    
        @Override
        public void deleteUser() {
            System.out.println("deleteUser");
        }
    
    }

    复制代码

  • 代理类设计
  • 复制代码

    package com.heima_aop;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Proxy;
    
    public class ProxyFactoryBean {
    
        public static UserService createUserService() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
            // 目标类
            final UserService service = new UserServiceImpl();
            // 切面类
            final MyAspect aspect = new MyAspect();
            
            //处理类
            MyInvocationHandler handler = new MyInvocationHandler(service);
            
            /**
             * 生成代理对象字节码
             */
            Class<?> proxyClass = Proxy.getProxyClass(ProxyFactoryBean.class.getClassLoader(), new Class[]{UserService.class});
            
            /**
             * 使用反射调用代理类对象的构造函数,通过InvocationHandler接口进行规范,InvocationHandler的接口实现类对象告知其具体处理方式
             */
            UserService proxy = (UserService) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
            
            /*
             * 方法二:
             * UserService proxy = (UserService) Proxy.newProxyInstance(
                    ProxyFactoryBean.class.getClassLoader(),
                    new Class[] { UserService.class },
                     new MyInvocationHandler(service));
                     
                方法三:(使用匿名内部类,官方推荐)    
                    UserService proxy =(UserService) Proxy.newProxyInstance(
                    ProxyFactoryBean.class.getClassLoader(),
                    new Class[] { UserService.class },InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method,
                                Object[] args) throws Throwable {
                            aspect.Before();
                            Object obj = method.invoke(service, args);
                            aspect.After();
                            return obj;
                        }
                    });            
                    */
            return proxy;
        }
    }

    复制代码

  • 测试
  • 复制代码

    package com.heima_aop;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Testdemo {
        @Test
        public void test_jdk(){
            String xmlpath = "com/heima_aop/bean.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlpath);
            UserService service = (UserService) applicationContext.getBean("Userservice");
            service.addUser();
            service.deleteUser();
            /*System.out.println(service);*/
        } 
    }

    复制代码

猜你喜欢

转载自blog.csdn.net/java_green_hand0909/article/details/84848173