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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 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的流程。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
15天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
17天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
28天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
34 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
10天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
27 1
|
27天前
|
设计模式 网络协议 Java
05.静态代理设计模式
《静态代理设计模式》详细介绍了静态代理的基本概念、原理与实现、应用场景及优缺点。主要内容包括静态代理的由来、定义、使用场景、实现方式、结构图与时序图,以及其在降低耦合、保护对象权限等方面的优势。同时,文章也指出了静态代理的局限性,如缺乏灵活性、难以复用、难以动态添加功能等,并介绍了动态代理如何弥补这些不足。最后,通过多个实际案例和代码示例,帮助读者更好地理解和应用静态代理模式。
33 4
|
30天前
|
Java 调度 开发者
spring的@Scheduled()有几种定时模式?
【10月更文挑战第12天】spring的@Scheduled()有几种定时模式?
71 1
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
21 3
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
1月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
404 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具