SpringAop动态代理(proxy)两种实现方式 JDK 和CGlib

举报
ksh1998 发表于 2021/12/25 23:02:47 2021/12/25
【摘要】 前言: 学习过spring的都知道,IOC和AOP是spring里最基础的两个核心技术。 在学习AOP(面向切面编程)的时候用到了动态代理,因为AOP的底层实现原理使用的就是动态代理。spring默认使用...

前言:
学习过spring的都知道,IOC和AOP是spring里最基础的两个核心技术。
在学习AOP(面向切面编程)的时候用到了动态代理,因为AOP的底层实现原理使用的就是动态代理。spring默认使用的是jdk提供的动态代理,其实是两种都支持。

什么是动态代理?

在了解动态代理之前,我现在简单介绍下什么代理。代理:按照字面意思,就是代替你去做一些事情。代替你去完成一些功能,或者做一些本来应该你来做的事情。这是字面意思理解,在面向对象的程序设计语言里:动态代理是在你原有的功能基础之上,对功能进行增强的一种实现手段。通过动态代理,并且符合开闭原则的前提增强方法的功能。这也是AOP的思想,通过不修改原有代码,把你的代码织入到指定的方法中。

代理模式:

代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
代理模式的元素是:共同接口、代理对象、目标对象。
代理模式的行为:由代理对象执行目标对象的方法、由代理对象扩展目标对象的方法。
代理模式的宏观特性:对客户端只暴露出接口,不暴露它以下的架构。

JDKProxDynameic 和 CGlibProxDynameic区别

jdk的动态代理是代理的接口,并且只能代理有 接口的类。如果这个类没有实现任何接口,jdk的动态代理是无法代理的。
这个时候就可以使用cglib去对类的字节码进行底层的继承代理,通过继承被代理对象。也就是JDKProxDynameic 代理的接口 CGlibProxDynameic代理的类(如果类被final修饰就不能被代理成功)

两种动态代理实现方式:

JDKProxDynameic(jdk提供)

jdk的动态代理主要是:
InvocationHandler接口和proxy类
在这里插入图片描述
import java.lang.reflect.InvocationHandler; 接口
InvocationHandler这个接口里主要是使用invoke方法,增强被代理对象的方法。在这里插入图片描述
参数:proxy 代理的实例
method 调用需要执行的方法
args 方法的参数

import java.lang.reflect.Proxy; 代理类
proxy类使用newProxyInstance方法创建新的代理实例在这里插入图片描述
参数:CLassLoader loader 代理对象的类加载器,用哪个类加载器去加载代理对象
Class<?> interfaces 被代理的接口数组
InvocationHandler h 调用处理器,也就是具体调用那个invoke方法。

代码实现:

被代理接口

 package com.proxys.proxy;

/**
 * @author 康世行
 * @Title:
 * @Package com.kuang.proxy
 * @Description:
 * @date 2021-07-21 9:04
 */
public interface A {
   public void a();
   public void b();
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

被代理接口实现类

package com.proxys.proxy;

/**
 * @author 康世行
 * @Title:
 * @Package com.kuang.proxy
 * @Description:
 * @date 2021-07-21 14:46
 */
public class testimpl implements A{
    @Override
    public void a() {
        System.out.println("测试动态代理");
    }

    @Override
    public void b() {
        System.out.println("代理了b方法");
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

代理对象

package com.proxys.proxy;

import com.kuang.springbootdemo.controller.Itest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author 康世行
 * @Title:
 * @Package com.kuang.proxy
 * @Description: jdk动态代理
 * @date 2021-07-21 14:28
 */
public class JdkDynamicProxyTest implements InvocationHandler {
    //被代理的接口
    private A a;
   //给具体的接口赋值
    public JdkDynamicProxyTest(A itest) {
      this.a=itest;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行了invoke方法");
        return method.invoke(a,args);//确定要执行那个对象的方法
    }
    //实例化动态代理
    public static A newProxyInstance(A itest){
        return (A) Proxy.newProxyInstance(JdkDynamicProxyTest.class.getClassLoader(),new Class[]{A.class},new JdkDynamicProxyTest(itest));
    }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

测试代码

 @Test
    void contextLoads() throws Exception {
       //创建测试对象(被代理对象)
        A a=new testimpl();
        //jdk动态代理实现,获取代理对象
        A jdkDynamicProxyTest = JdkDynamicProxyTest.newProxyInstance(a);
        jdkDynamicProxyTest.a();
        jdkDynamicProxyTest.b();
    }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

测试结果:
在这里插入图片描述

CGlibProxDynameic(spring提供)

cglib动态代理主要是:
MethodInterceptor 方法拦截接口和Enhancer 增强类
在这里插入图片描述
MethodInterceptor 方法拦截接口里主要是使用 intercept方法对父方法进行拦截,然后增强父方法的功能。
在这里插入图片描述
然后使用Enhancer增强类 里的create方法创建代理对象
在这里插入图片描述

代码实现:

被代理对象使用上面JDKProxDynameic 里的A接口的实现类testimpl
代理对象

package com.kuang.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author 康世行
 * @Title:
 * @Package com.kuang.proxy
 * @Description: cglib动态代理
 * @date 2021-07-21 15:18
 */
public class cglibProxyTestt implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("intercept执行完毕");
        return methodProxy.invokeSuper(o,objects);
    }
    //产生cglibproxy动态代理(通过底层字节码继承,实现动态代理;注意,如果类被final修饰怎代理失败)
    public static <T extends A> A newProxyInstance(Class<T> targetInstanceClazz){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(targetInstanceClazz);
        enhancer.setCallback(new cglibProxyTestt());
        return (A) enhancer.create();//创建动态代理
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

测试代码

   @Test
    void contextLoads() throws Exception {
       //创建测试对象(被代理对象)
        A a=new testimpl();
         
        // cglib创建动态代理对象
        A cglibProxyTest = cglibProxyTestt.newProxyInstance(testimpl.class);
        cglibProxyTest.a();
        cglibProxyTest.b();
    }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

测试结果
在这里插入图片描述

感谢阅读 ~~~~

文章来源: kangshihang.blog.csdn.net,作者:康世行,版权归原作者所有,如需转载,请联系作者。

原文链接:kangshihang.blog.csdn.net/article/details/119007661

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。