JDK代理和Cglib代理实现和区别

原创 2018年04月17日 09:54:14

一.JDK代理实现

接口类

public interface UserManager {
    void addUser(@NotBlank String username, @NotNull(message = "javax.validation.constraints.NotNull.message") String password);

    void delUser(int userId);

    String findUserById(int userId);
}

实现类

public class UserManagerImpl implements UserManager {

    @Override
    public void addUser(String username, String password) {
        System.out.println("addUser:" + username + "," + password);
    }

    @Override
    public void delUser(int userId) {
        System.out.println("delUser:" + userId);
    }

    @Override
    public String findUserById(int userId) {
        System.out.println("findUserById:" + userId);
        return String.valueOf(userId);
    }
}

代理类

public class SecurityHandler implements InvocationHandler {
    private Object targetObject;

    public Object createProxyInstanceObject(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        checkSecurity();
        return method.invoke(targetObject,args);
    }

    private void checkSecurity(){
        System.out.println("-----------checkSecurity----------");
    }
}

二.CgLib代理实现

实现类

public class UserService {

    public void addUser(String username, String password) {
        System.out.println("addUser:" + username + "," + password);
    }

    public void delUser(int userId) {
        System.out.println("delUser:" + userId);
    }

    public String findUserById(int userId) {
        System.out.println("findUserById:" + userId);
        return String.valueOf(userId);
    }
}

代理类

public class CglibProxy implements MethodInterceptor {
    private Object targetObject;

    public Object createProxyInstanceObject(Object targetObject) {
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetObject.getClass());
        enhancer.setCallback(this);
        return  enhancer.create();
        //return targetObject;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = null;
        //obj = methodProxy.invokeSuper(o, objects);
        obj = method.invoke(targetObject, objects);
        after();
        return obj;
    }

    private void before() {
        System.out.println("-----------before----------");
    }

    private void after() {
        System.out.println("-----------after----------");
    }
}

三.测试

public class App {
    public static void proxyManager() {
        SecurityHandler securityHandler = new SecurityHandler();
        UserManager userManager = (UserManager) securityHandler.createProxyInstanceObject(new UserManagerImpl());
        userManager.addUser("张飞", null);
    }

    public static void proxyService() {
        SecurityHandler securityHandler = new SecurityHandler();
        UserService userService = (UserService) securityHandler.createProxyInstanceObject(new UserService());
        userService.addUser("李四", null);
    }

    public static void main(String[] args) {
        cglibProxyManager();
    }

    public static void cglibProxyService() {
        CglibProxy proxy = new CglibProxy();
        UserService userService = (UserService) proxy.createProxyInstanceObject(new UserService());
        userService.findUserById(1234);
    }
    public static void cglibProxyManager() {
        CglibProxy proxy = new CglibProxy();
        UserManager userManager = (UserManager) proxy.createProxyInstanceObject(new UserManagerImpl());
        userManager.findUserById(1234);
    }
}

运行结果会发现方法proxyService报错。

提出问题:

1.Enhancer类的作用

    生成代理类,用来继承被代理对象

2.obj.invoke 和 obj.invokeSuper两种写法的区别

    一般使用invokeSuper(obj,args)方法。执行原始类的方法。方法.invoke,这是执行生成子类的方法。如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不停的进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。
  我们来看看MethodProxy,原始类里每一个方法都会在动态的子类里有一个对应的MethodProxy,而一个MethodProxy又对应了两个动态生成的FastClass类,一个是对应原始方法,一个对应新生成的子类,MethodProxy.invokeSuper就是交给对应原始方法那个FastClass,MethodProxy.invoke交给另一个。

3.proxyService方法为什么会报错

    核心在于ProxyGenerator.generateProxyClass

    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }
private byte[] generateClassFile() {
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }

        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }

        Iterator var15;
        try {
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();

            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    this.methods.add(var16.generateMethod());
                }
            }

            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }

        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;

            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }

            this.cp.setReadOnly();
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);

            try {
                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
                Class[] var17 = this.interfaces;
                int var18 = var17.length;

                for(int var19 = 0; var19 < var18; ++var19) {
                    Class var22 = var17[var19];
                    var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                }

                var14.writeShort(this.fields.size());
                var15 = this.fields.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                    var20.write(var14);
                }

                var14.writeShort(this.methods.size());
                var15 = this.methods.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                    var21.write(var14);
                }

                var14.writeShort(0);
                return var13.toByteArray();
            } catch (IOException var9) {
                throw new InternalError("unexpected I/O Exception", var9);
            }
        }
    }
1.在需要继承proxy类获得有关方法和InvocationHandler构造方法传参的同时,java不能同时继承两个类,我们需要和想要代理的类建立联系,只能实现一个接口
2.需要反射获得代理类的有关参数,必须要通过某个类,反射获取有关方法,如本次测试用的 :printSomeThing
3.成功返回的是object类型,要获取原类,只能继承/实现,或者就是那个代理类
4.对具体实现的方法内部并不关心,这个交给InvocationHandler.invoke那个方法里去处理就好了,我只想根据你给我的接口反射出对我有用的东西。
5.考虑到设计模式,以及proxy编者编写代码的逻辑使然

结论:

JDK代理和Cglib代理的区别

 JDK代理Cglib代理
实现

InvocationHandle

底层使用反射机制进行方法的调用r

MethodInterceptor

底层将方法全部存入一个数组中,通过数组索引直接进行方法调用

优点不需要硬编码接口,代码复用率高可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口
缺点只能够代理实现了接口的委托类不能对final类以及final方法进行代理




版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lipp555/article/details/79969941

JDK动态代理和CGLIB代理的区别

JAVA的动态代理  代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类...
  • samrtian
  • samrtian
  • 2016-01-27 19:36:30
  • 1930

Java动态代理模式jdk和cglib的2种实现以及二者的区别(AOP面向切面的前奏)

关于动态代理模式里面有两种实现,一种是jdk实现,一种是cglib来实现。 下面来整jdk来实现动态代理的Java实例。 jdk动态代理模式里面有个拦截器的概念,在jdk中,只要实现了Invocati...
  • qq_27093465
  • qq_27093465
  • 2016-11-25 21:40:04
  • 3830

Java JDK代理、CGLIB、AspectJ代理分析比较

前言 什么是代理,在Design patterns In java这个本书中是这样描述的,简单的说就是为某个对象提供一个代理,以控制对这个对象的访问。在不修改源代码的基础上做方法增强,代理是一种设计...
  • a837199685
  • a837199685
  • 2017-03-31 20:19:36
  • 1596

Spring—AOP两种代理机制对比(JDK和CGLib动态代理)

Sprign 动态代理机制 Spirng的AOP的动态代理实现机制有两种,分别是: 1)JDK动态代理: 具体实现原理: 1、通过实现InvocationHandlet接口创建自己的调...
  • qq1723205668
  • qq1723205668
  • 2017-02-22 12:09:55
  • 4536

设计模式-代理模式(jdk代理和cglib代理详解)

说起代理模式,详细很多人早已经很理解,但对于我这个菜鸟,理解的可能还是不到位,写一次博客加深印象。 什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要...
  • qq_27717967
  • qq_27717967
  • 2017-06-22 11:24:42
  • 580

动态代理proxy与CGLib的区别

昨天被人问及动态代理与CGlib的区别,赶紧回顾一下: 什么是代理?静态代理与动态代理静态代理实例JDK动态代理实例CGLib 简介CGLib 与JDK动态代理的区别     代理模式是Java...
  • hintcnuie
  • hintcnuie
  • 2013-09-03 08:50:56
  • 24632

jdk动态代理与CGLib的区别

动态代理proxy与CGLib的区别 标签: 代理模式 2013-09-03 08:50 19977人阅读 评论(4) 收藏 举报 版权声明:本文为博主原创...
  • qq_34310242
  • qq_34310242
  • 2017-09-20 22:31:10
  • 63

基于JDK动态代理和CGLIB动态代理到底有什么区别?

转自:基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别摘要结论: 基于JDK动态代理 ,可以将@Transactional放置在接口和具...
  • flysharkym
  • flysharkym
  • 2017-01-03 19:54:40
  • 814

【Spring AOP】【AspectJ】【CGLIB】【JDK动态代理】【JDK静态代理】区别

今天复习了一下AOP相关概念。 有这么几个知识名词需要好好理解一下。 基本上可以概括为动态和静态两类 【动态】CGLIB、JDK动态代理、Spring AOP 【静态】AspectJ、JDK静态代理...
  • yanxin007
  • yanxin007
  • 2017-01-10 13:22:50
  • 2142

JDK和Cglib实现动态代理实例及优缺点分析

Spring AOP使用的核心技术是动态代理,说到动态代理就不得不和设计模式中的代理模式联系起来,通过代理模式我们可以对目标类进行功能增强,在某个方法的执行前后增加一些操作,例如计算方法执行效率、打印...
  • Rongbo_J
  • Rongbo_J
  • 2015-10-17 13:38:53
  • 4380
收藏助手
不良信息举报
您举报文章:JDK代理和Cglib代理实现和区别
举报原因:
原因补充:

(最多只允许输入30个字)