spring源码设计模式分析-代理设计模式(二)

简介: spring源码设计模式分析-代理设计模式(二)

昨天写的四种建造者的设计模式是在spring中用BeanDefinitionBuilder来动态构建bean定义对象时创建的在IOC容器中,所有的操作都是基于bean对象来操作的,在spring中用的是深拷贝的模式,spring中常用的设计模式是13种,还有一种设计模式是桥接的设计模式,主要用到泛型的会用到。

结构型设计模式:

1、代理设计模式:当我们看spring的aop的时候会用到代理设计模式,主要用来创建bean的代理对象的,因为aop的核心是进行横切,本质将bean定义的对象,然后创建一个代理对象,

来以偷听换玉的方式将bean的定义对象换成代理对象,然后这个容器种中bean本身的对象就不存在了,全部由代理对象来操作,@Autowired和@Resource在依赖注入的时候,全部注入的是aop代理对象,在代理设计模式中一种是jdk的,一种是cglib的,在spring中大多数都是cglib代理,代理就是代理别人的功能。

1.1、JdkDynamicAopProxy :jdk动态代理,用来创建接口代理对象

1.2、CglibAopProxy:动态代理,用来创建类的代理对象

静态代理:

①、首先创建一个接口:

  1. package com.weizhaoyang.proxy;

  2. /**
  3. * 业务服务接口
  4. */
  5. public interface DemoService{
  6. /**
  7.     * 业务服务demo
  8.     */
  9. publicString  demo();
  10. /**
  11.     * 业务服务2
  12.     */
  13. //public  void  demo2();
  14. }

②、创建一个实现类:

  1. package com.weizhaoyang.proxy;

  2. public class DemoServiceImpl implements  DemoService {
  3.    @Override
  4.    public String demo(String name) {
  5.        System.out.println("我需要记录日志");
  6.        return "weizhaoyang";
  7.    }
  8. }

创建一个静态代理的类:

  1. package com.weizhaoyang.proxy;

  2. /**
  3. * DemoService的静态代理
  4. *
  5. */
  6. public class DemoServiceStaticProxy implements DemoService {
  7.    //加一个属性DemoService,全部由代理类来控制掉,所以要依赖进来,也就是一种封装,只由代理类来控制
  8.    private DemoService demoService;
  9.    public DemoServiceStaticProxy(DemoService demoService){
  10.        this.demoService=demoService;
  11.    }

  12.    @Override
  13.    public String demo(String name) {
  14.        System.out.println("代理执行之前");
  15.        demoService.demo(name);
  16.        System.out.println("代理执行之后");
  17.        return "weizhaoyang";
  18.    }
  19. }

创建一个测试类:

  1. package com.weizhaoyang.proxy;

  2. public class DemoTest1 {

  3.        public static void main(String[] args) {
  4.            DemoService demoService= new DemoServiceImpl();
  5.            //创建一个代理类的对象,来把demoService这个对象给 控制住
  6.            DemoService  demoService2=new DemoServiceStaticProxy(demoService);
  7.            //然后再DemoService这个接口之上完成自己的功能
  8.            System.out.println(demoService2.demo("weizhaoyang"));


  9.    }
  10. }

运行的结果如下:

在Spring的ioc容器里面相当于用这个代理对象将DemoService对象全部替换掉了这就是代理对象能代替对象的根本原因

缺点:

1、静态代理必须要依赖原有的对象

2、每加一个需求都需要改三个地方,接口,实现类,代理类,不好维护。

在java中一个代理类只能控制一个行为

解决上面的缺点:

1、通过反射动态代理就是基于反射来操作的,通过Method来动态执行接口中所有的方法,就是把接口中的方法抽象成一个Method对象传进来操作,反射虽然效率不高,但是提高了代码的灵活性。

2、用jdk动态代理来实现,就是基于反射来实现的,让类来实现InvocationHandler,通过代理对象调用invoke方法

代码如下:首先提供一个抽象的业务接口,把这个接口可以当作成service,也可以当作成具体的对象。

  1. package com.weizhaoyang.proxy;

  2. /**
  3. * 业务服务接口
  4. */
  5. public interface DemoService{
  6. /**
  7.     * 业务服务demo
  8.     */
  9. publicString  demo();
       


  10. }

提供 一个实现类:我这个行为需要产生日志记录

  1. package com.weizhaoyang.proxy;

  2. public class DemoServiceImpl implements  DemoService {
  3.    @Override
  4.    public String demo(String name) {
  5.        System.out.println("我需要记录日志");
  6.        return "weizhaoyang";
  7.    }
  8. }

提供一个动态代理的类:

  1. package com.weizhaoyang.proxy;

  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.sql.SQLOutput;

  7. /**
  8. * InvocationHandler执行处理器
  9. */
  10. public class DemoServiceProxy implements InvocationHandler {
  11.    //依赖目标类
  12.    private DemoService demoService;
  13.    public DemoServiceProxy(DemoService demoService) {
  14.        this.demoService=demoService;
  15.    }
  16.    public  Object getProxy(){
  17.        return Proxy.newProxyInstance(DemoService.class.getClassLoader(),new Class[]{DemoService.class},this);
  18.    }
  19.    //通过反射委托调用执行invoke方法,代理方法
  20.    @Override
  21.    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  22.        //记录开始日志
  23.        System.out.println("方法执行前打印日志");
  24.        //开始执行方法,调用自己的方法
  25.        Object object= null;
  26.        try {
  27.            object = method.invoke(demoService,args);
  28.        } catch (RuntimeException e) {
  29.           e.getMessage();
  30.        }
  31.        //3、记录日志
  32.        System.out.println("方法执行后打印日志");
  33.        if(object.equals("weizhaoyang")){
  34.            System.out.println("方法返回值通知");
  35.            throw new RuntimeException("异常通知");
  36.        }
  37.        return object;
  38.    }
  39. }

写个测试类:

  1. package com.weizhaoyang.proxy;

  2. public class DemoTest1 {

  3.        public static void main(String[] args) {
  4.           /* DemoService demoService= new DemoServiceImpl();
  5.            //创建一个代理类的对象,来把demoService这个对象给 控制住
  6.            DemoService  demoService2=new DemoServiceStaticProxy(demoService);
  7.            //然后再DemoService这个接口之上完成自己的功能
  8.            System.out.println(demoService2.demo());
  9. */
  10.          //创建被代理对象
  11.            DemoService demoService=new DemoServiceImpl();
  12.           //创建代理的对象
  13.            DemoServiceProxy demoServiceProxy=new DemoServiceProxy(demoService);
  14.            //获取被代理的对象
  15.            DemoService service= (DemoService) demoServiceProxy.getProxy();
  16.           service.demo("weizhaoyang");
  17.    }
  18. }

运行的结果如下:

解释下、getProxy方法中的参数的作用:

方法中的参数:new Class[]{DemoService.class}:把接口当作参数传进去   this:代表传InvocationHandler对象, DemoService.class.getClassLoader():将类加载器传进来,类加载器可以自定义,防止在定义接口的时候防止不是默认的加载器来加载道jvm里面的,所以需要传classloader ,InvocationHandler通过它来做一个桥梁将代理类和被代理做一个组合起来,然后将代理类对象去执行invoke方法,来动态的去调用本身的方法。

总结:

1、spring的aop就是基于上面的本质来操作的,所以在aop之中有前置通知,和后置通知还有方法返回值(执行完成之后,方法返回值没有返回)之后通知,还有一种是抛异常通知,可以在返回值之后抛异常,而在spring中把这几个通知封装成了各个的接口,封装的接口的意义在于去扩展,环绕通知是针对上面的四种一整套,前置通知和后置通知只是针对于方法的执行前后,这是jdk的动态的一种思路。

2、下面的就称之为springAOP中的抽象为前置通知。

下面的就称之为springAOP中的抽象为后置通知。

下面的就称之为springAOP中的抽象为异常通知。

下面的就称之为springAOP中的抽象为方法的返回值通知。

这个就称之为springAOP连接点joinPoint

这个就是SpringAop中的切入点,每一个切入点通过连接点来进行切入

然后把切点和通知封装为切面对象advice,然后动态的去植入,这就是aop的流程。

相关文章
|
7天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
3天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2436 13
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
3天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1480 14
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19268 29
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18816 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17513 13
Apache Paimon V0.9最新进展
|
1月前
|
存储 人工智能 前端开发
AI 网关零代码解决 AI 幻觉问题
本文主要介绍了 AI Agent 的背景,概念,探讨了 AI Agent 网关插件的使用方法,效果以及实现原理。
18695 16
|
5天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
321 11
|
2天前
|
算法 Java
JAVA并发编程系列(8)CountDownLatch核心原理
面试中的编程题目“模拟拼团”,我们通过使用CountDownLatch来实现多线程条件下的拼团逻辑。此外,深入解析了CountDownLatch的核心原理及其内部实现机制,特别是`await()`方法的具体工作流程。通过详细分析源码与内部结构,帮助读者更好地理解并发编程的关键概念。
|
2天前
|
SQL 监控 druid
Druid连接池学习
Druid学习笔记,使用Druid进行密码加密。参考文档:https://github.com/alibaba/druid
184 80