精华内容
下载资源
问答
  • 动态代理的两种方式
    千次阅读
    2022-01-05 16:15:34

    动态代理的两种方式:JDK方式和cglib方式。

    一.JDK方式,在这个方式中,需要目标对象,目标对象的接口,增强方法,三个类。

    public interface TargetInterface {
        public void save();
    }

    public class Target implements TargetInterface{
        @Override
        public void save() {
            System.out.println("saving");
        }
    }
    

    创建了简单的目标类,用于被增强。接下来创建增强方法类。

    public class Advance {
        public void before(){
            System.out.println("前置增强");
        }
    
        public void after(){
            System.out.println("后置增强");
        }
    }

    创建测试类,增强target的功能。

    public class ProxyTest {
        public static void main(String[] args) {
            Target target = new Target();
            Advance a = new Advance();
            TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    a.before();
                    method.invoke(target,args);
                    a.after();
                    return null;
                }
            });
            proxy.save();
        }
    }

    在main方法中对target方法进行了增强,增强的主要代码在invoke()方法内部实现。

    二,使用cglib

    使用cglib需要引入对应的jar包或者maven坐标(针对于老版本的spring而言,新版本的spring5已经在core包下包含了cglib)。

    public class Target{
        @Override
        public void save() {
            System.out.println("saving");
        }
    }
    
    public class Advance {
        public void before(){
            System.out.println("前置增强");
        }
    
        public void after(){
            System.out.println("后置增强");
        }
    }

    同样的有如上类的创建。不过在测试类中就不一样了

    public class ProxyTest {
        public static void main(String[] args) {
            Target target = new Target();
            Advance a = new Advance();
            //1.创建增强器
            Enhancer enhancer = new Enhancer();
            //2.设置父类
            enhancer.setSuperclass(Target.class);
            //3.设置回调
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    a.before();
                    Object invoke = method.invoke(target, objects);
                    a.after();
                    return invoke;
                }
            });
            //4.设置代理对象
            Target target1 = (Target) enhancer.create();
            target1.save();
        }
    }

    设置回调时的intercept方法就如同第一种方法中的invoke方法。

    更多相关内容
  • 动态代理两种方式及比较

    千次阅读 2017-05-24 01:11:33
     AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。...

    这学期来一直在看面经,反而很少动手去写东西了,今天就破一次例动动贱手!

     AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。

    那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。

    AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。。

    下来贴上jdk动态代理的代码

    1,定义接口以及实现类

    interface Say{
    	void sayYes();
    }
    /**
     * 被代理类,使用jdk的动态代理必须实现一个接口
     * @author zhangchao
     *
     */
    class SayYes implements Say{
    	@Override
    	public void sayYes() {
    		System.out.println("长草,Yes!");
    	}
    }

    2,jdk动态代理类的实现

    class Jdk implements InvocationHandler{
    	//被代理的实例
    	Object obj;
    	public Jdk(Object obj) {
    		//将被代理者的实例传进动态代理类的构造函数中
    		this.obj=obj; 
    	}
    	//覆盖InvocationHandler接口的invoke()方法
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		System.out.println("前置代理");
    		Object result=method.invoke(this.obj, args);
    		System.out.println("后置代理");
    		return result;
    	}
    }

    3,测试

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    /**
     * 被代理类必须实现接口
     * jdk动态代理
     * @author zhangchao
     *
     */
    public class JdkProxy {
    	public static void main(String[] args) {
    		Say say=new SayYes();
    		InvocationHandler handler=new Jdk(say);
    		Say proxyImp=(Say)Proxy.newProxyInstance(handler.getClass().getClassLoader(), say.getClass().getInterfaces(), handler);
    		proxyImp.sayYes();
    	}
    }

    测试结果如下:

    前置代理
    张超,Yes!
    后置代理
    


    Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:

    CGLIB的核心类:
        net.sf.cglib.proxy.Enhancer – 主要的增强类
        net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
        net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
        Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

    net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
    public Object intercept(Object object, java.lang.reflect.Method method,
    Object[] args, MethodProxy proxy) throws Throwable;

    第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

    接下来继续上cglib的程序

    1,定义被代理类

    /**
     * 被代理类,使用cglib可以不必实现接口
     */
    class SayHello{
    	public void say(){
    		System.out.println("hello 张超!");
    	}
    }


    2,cglib代理类的实现

    class Cglib implements MethodInterceptor{
    	private Enhancer enhancer=new Enhancer();
    	public Object getProxy(Class<?> clazz){
    		//设置需要创建子类的类
    		enhancer.setSuperclass(clazz);
    		enhancer.setCallback(this);
    		//通过字节码技术动态创建子类实例
    		return enhancer.create();
    	}
    	//覆盖MethodInterceptor接口的intercept方法
    	@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("后置代理");
    		return result;
    	}
    }


    3,测试

    import java.lang.reflect.Method;
    
    import org.mockito.cglib.proxy.Enhancer;
    import org.mockito.cglib.proxy.MethodInterceptor;
    import org.mockito.cglib.proxy.MethodProxy;
    /**
     * 	被代理类可以实现接口,也可不实现接口
     *  cglib动态代理
     *  CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,
     *  使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
     * @author zhangchao
     *
     */
    public class CglibProxy{
    	public static void main(String[] args) {
    		Cglib proxy=new Cglib();
    		//通过生成子类的方式创建代理类
    		SayHello proxyImp=(SayHello)proxy.getProxy(SayHello.class);
    		proxyImp.say();
    	}
    }


    测试结果

    前置代理
    hello 张超!
    后置代理
    


    此处注意 ,如果使用的cglib-2.2.2.jar包的话,可能会出现异常,具体异常名字没注意记,网上说是jar冲突,可是我这个测试工程中就只放置了一个cglib包,不存在任何冲突,无奈,换了另一个开元包:mockito-all-1.10.19.jar




    展开全文
  • 动态代理 两种方式

    千次阅读 2017-08-17 10:51:21
    代理类Proxy和RealSubject应该实现了相同的功能接口,在面向对象的编程之中,如果想要两个对象实现相同的功能,有以下两种方式: 1)定义一个功能接口,然后代理类Proxy和真实类RealSubject都实现这个接口。 2)...

    1、动态代理概述

    代理类Proxy和RealSubject应该实现了相同的功能接口,在面向对象的编程之中,如果想要两个对象实现相同的功能,有以下两种方式:

    1. 1)  定义一个功能接口,然后代理类Proxy和真实类RealSubject都实现这个接口。
    2. 2)  代理类Proxy继承RealSubject,这样Proxy则拥有了RealSubject的功能,Proxy还可以通过重写RealSubject中的方法,来实现多态。 

    其中JDK中提供的创建动态代理的机制就是以1方式设计的,而cglib则是以2方式设计的。

    2、JDK的动态代理机制

    Jdk为RealSubject对象创建动态代理对象,主要做了以下工作:

    1. 1) 获取RealSubject上的所有接口列表。
    2. 2) 确定要生成的动态代理类的类名,默认为com.sun.proxy.$ProxyXXX
    3. 3) 根据需要实现接口信息,在代码中动态创建该Proxy的字节码
    4. 4) 将对应的字节码转换为对应的class对象
    5. 5) 创建InvocationHandler实例,用来处理Proxy所有方法调用
    6. 6) Proxy的class对象以创建的handler对象为参,实例化Proxy对象

    Jdk通过java.lang.reflect.Proxy来支持动态代理,一般情况下,使用方法newProxyInstanceof来创建Proxy类,而对于InvocationHandler,需要实现它的invoke方法,在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。

    3、cglib的动态代理机制

    JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法,果某个类没有实现接口,那么这个类就不能同JDK产生动态代理了!CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

    cglib 创建某动态代理类的模式是:

    1. 1)  查找类上的所有非final的public类型的方法定义
    2. 2)  将这些方法的定义转换成字节码
    3. 3)  将组成的字节码转换成相应的代理的class对象
    4. 4)  实现MethodInterceptor接口,用来处理对代理类上所有方法的请求(和InvocationHandler的功能和角色是一样的)cglib需要的jar包有asm.jar、cglib.jar

    如有披露或问题欢迎留言或者入群探讨

    展开全文
  • 1)jdk Proxy.newInstance(ClassLoader loader,Interface[] ...这种方法主要是代理接口,不能代理类。 第一步实现invocationHandler接口 public class Proxy implements InvocationHandler{ private TestInterf...

    1)jdk Proxy.newInstance(ClassLoader loader,Interface[] interfaces,Class clazz);

    这种方法主要是代理接口,不能代理类。

    第一步实现invocationHandler接口

    public class Proxy implements InvocationHandler{
    
        private TestInterface object;
    
        public Proxy(TestInterface testItf){
            this.object = testItf;
        }
    
        public PersonAction getInstace(){
            return (TestInterface) Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{TestInterface.class},this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("args are "+method.getName());
            // 在调用实际方法之前可以做很多前置操作
            return method.invoke(pa,args);
        }
    }

    然后就是写一个TestInterface的接口和两个实现了该接口的实现类,

    public interface TestInterface {
        void bigAct();
    }
    
    public class Programmer implements TestInterface {
        public void bigAct(){
            println("i do program every day.i can be a great programmer.");
        }
    }
    
    public class Dancer implements TestInterface {
        public void bigAct(){
            println("i dance every day.i can be a great dancer.");
        }
    }

    测试代理类

    public class ActionMain {
    
            public static void main(String[] args) {
                Programmer p2 = new Programmer();
    
                TestInterface p = new Proxy(p2).getInstace();
                p.bigAct();
                //这里看到p2注入到Proxy中,并返回了一个Instance对象,然后再执行p的bigAct方法。
                //具体Proxy.newInstance()实现是通过        
                //class.getConstructor().newInstance(Invocationhandler);
                //即 ConstructorAccessor.newInstance(Object[] var1);
                //我们可以在调用具体的方法前,做很多前置或者是后置操作,这也是aop的思想。
            }
    }
    
    
    public interface ConstructorAccessor {
        Object newInstance(Object[] var1) throws InstantiationException, IllegalArgumentException, InvocationTargetException;
    }

     

    2)CGLib动态代理

    第一步实现代理类

    public class ProxyCglib implements MethodInteceptor{
    
        Object obj;
    
        public Object newInstance(Object object){
            this.obj = object;
            Enhancer enhancer = new Enhancer();
            enhancer.setCallback(this);
            enhancer.setSuperClass(object.getClass());
            return enhancer.create();
        }
    
        @Override
        public void intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {
            return method.invoke(obj,args);//两种方式都是通过反射来实现方法的调用。
        }
    }

    和jdk动态代理的区别就是cglib可以代理类,而jdk只能代理接口,如果没有实现接口,就代理不了,springboot动态代理自动在两者之间切换,如果类实现了接口就用jdk如果没有就用cglib。当然cglib动态代理还要引入asm的jar包。

    两者代理的原理区别是:反射调用和fastclass引用

    https://www.cnblogs.com/monkey0307/p/8328821.html   这篇文章给出了原理。

    cglib 调用过程:代理对象执行 MethodA() ->拦截器methodInterceptor ->methodProxy.invokeSuper() ->被代理对象 执行方法,

    之所以快就是因为asm包为代理类和被代理类的方法生成的fastClass,对应的是一个index,这样就可以根据这个index执行对应的方法,而j'd'k是使用反射调用。

    > 原文如下:

    调用过程:代理对象调用this.setPerson方法->调用拦截器->methodProxy.invokeSuper->CGLIB$setPerson$0->被代理对象setPerson方法

    Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,
    这个Class会为代理类或被代理类的方法分配一个index(int类型)。这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,
    这样省去了反射调用,

     

    https://blog.csdn.net/yhl_jxy/article/details/80633194  这篇文章亦然。

    展开全文
  • SpringAop动态代理两种实现方式

    千次阅读 2021-08-18 22:54:52
    Spring的面向切面编程也是基于动态代理来实现的 ...那么在Spirng当中动态代理两种 第一种也就是JDK自带的动态代理 1.JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用In
  • 动态代理两种方式以及区别

    万次阅读 多人点赞 2018-09-19 12:37:09
    动态代理两种方式,以及区别。 JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将...
  • 动态代理两种方式以及优缺点

    千次阅读 2019-03-20 14:55:44
    动态代理应用非常的广泛,在各种开源的框架中都能看到他们的身影,比如spring中的aop使用动态代理增强,mybatis中使用动态代理生成mapper,动态代理主要有JDK和CGLIB两种方式,今天来学习下这两种方式的实现,以及...
  • 什么是动态代理?假如我有一个user对象,该对象里面有4个方法,增、删、改、查,外界能直接调用这4个方法吗?拿百度来说,你能随便对百度上的内容进行增、删、改、查操作吗?你最多能执行查的操作,增、删、改的操作...
  • 上篇介绍了一下静态代理:Java中的代理模式——静态代理以及分析静态代理的缺点 也分析了一下静态代理的缺点: 1、由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要...
  • Spring动态代理两种方式

    千次阅读 2022-04-21 14:45:01
    Spring动态代理两种方式1. Spring创建的动态代理类在哪⾥?1.1 什么叫动态字节码技术?2. 1. Spring创建的动态代理类在哪⾥? Spring 框架在运行时,通过字节码技术,在jvm创建的,运营在jvm内部,等程序结束后,...
  • 动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,...
  • AOP两种动态代理方式

    千次阅读 2020-09-28 14:26:56
    Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由 AopProxyFactory 根据AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口, 则使用 JDK 动态代理技术,否则使用 ...
  • Spring AOP动态代理两种实现方式

    万次阅读 2021-01-14 22:30:04
    Spring AOP动态代理两种实现方式 Aspect Oriented Programming 面向切面编程 通过预处理和运行期动态代理方式, 实现功能的统一维护 作用: 在运行期间, 不修改源码的情况下, 增加方法的功能 优势: 减少重复代码,...
  • 动态代理两种实现方式

    千次阅读 多人点赞 2019-10-15 18:41:48
    1.动态代理概述 代理模式:在不修改目标对象的情况下,对目标对象进行功能增强 动态代理的代理类在物理上是不存在的,代理类是在程序运行的时候产生的. 目标对象:被增强功能的对象 代理对象:用来对目标对象进行...
  • 什么是动态代理? 假如我有一个user对象,该对象里面有4个方法,增、删、改、查,外界能直接调用这4个方法吗?拿百度来说,你能随便对百度上的内容进行增、删、改、查操作吗?你最多能执行查的操作,增、删、改的...
  • 前言: 学习过spring的都知道,IOC和AOP是spring里...****代理模式:****JDKProxDynameic 和 CGlibProxDynameic区别**两种动态代理实现方式:JDKProxDynameic(jdk提供)代码实现:CGlibProxDynameic(spring提供)代码
  • Java两种动态代理JDK动态代理和CGLIB动态代理

    万次阅读 多人点赞 2018-08-07 15:33:35
    JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23设计模式的一,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是...
  • 动态代理-两种实现方式

    千次阅读 2018-05-06 10:20:47
    代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象... 按照代理的创建时期,代理类可以分为两种。 ...
  • AOP的两种代理方式

    千次阅读 2021-12-15 07:56:11
    AOP的两种代理方式
  • 动态代理两种方式和区别

    千次阅读 2020-05-05 00:28:50
    静态代理的缺点: 由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要创建100个代理类 如果一个Service中有很...JDK动态代理:利用反射机制生成一个实现代理接口的匿名类...
  • Spring动态代理两种区别

    万次阅读 2019-02-15 12:54:37
    Spring的面向切面编程也是基于动态代理来实现的 静态代理:也就是自己手动创建的代理对象 动态代理:也就是在程序运行中通过配置参生的 那么Spring的AOP也就是面向切面编程,...那么在Spirng当中动态代理两种 ...
  • Spring AOP两种动态代理对象实现方式

    千次阅读 2018-09-04 11:58:51
    一、JDK生成AopProxy代理对象 通过JDK的Proxy类的静态方法newProxyInstance方法得到最终的代理对象。该方法包含3个参数: /** 三个参数: 一个类装载器loader, 一个代理接口interfaces, 一个Proxy回调方法...
  • AOP两种动态代理的区别

    千次阅读 2018-08-26 16:35:32
    spring 中 AOP是基于 “动态代理” 实现,其采用了两种方式: java代理:采用java内置的代理API实现 cglib代理:采用第三方API实现 本文主要阐述这两种方式的区别 动态代理和静态代理 静态代理:编译时将增强...
  • Java动态代理两种实现方式

    千次阅读 2019-01-19 16:09:11
    一般而言,动态代理有以下两种实现方式 一、基于接口的动态代理(JDK动态代理) 要求:被代理类最少实现一个接口 提供者:jdk官方 例: /** * 演员类 */ public class Actor implements IActor{ public void ...
  • AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中。 一、AOP术语  1.连接点(Joinpoint)  程序执行的某个特定位置:如类开始初始化之前、类初始化之后、类某个方法调用前、调用....
  • JDK和Cglib两种动态代理方式区别 1、java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而Cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过...
  • AOP两种代理方式以及区别?

    千次阅读 2020-04-29 23:51:53
    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。 JDK 动态代理只能对实现了接口的类生成代理,而不能针对类. JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 ...
  • 1.两种动态代理方式演示 1.1 JDK动态代理 JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。要求被代理类必须实现一个接口 . 如下案例 接口 public ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 255,140
精华内容 102,056
关键字:

动态代理的两种方式