当前位置: 首页 > news >正文

剖析Spring中的设计模式(一) | 工厂观察者

 

目录

Spring中工厂模式的应用

Spring设计理念

Spring中Bean组件定义相关

BeanFactory源码&使用情景

Spring中的FactoryBean

为什么需要FactoryBean?

FactoryBean的使用特点?

使用场景

BeanFactory与FactoryBean区别

BeanFactory和ApplicationContext的区别

Spring中观察者模式应用

Spring中观察者模式

事件机制工作流程

监听器什么时候注册到IOC容器

Spring如何发布的事件并通知监听者


Spring设计模式内容,读者如果阅读过 自己实现Spring简易版解析 或许有不一样的感受哦

Spring中工厂模式的应用

Spring设计理念

  • Spring是面向Bean的编程(BOP:Bean Oriented Programming),Bean在Spring中才是真正的主角。Bean在Spring中作用就像Object对OOP的意义一样,没有对象的概念就像没有面向对象编程,Spring中没有Bean也就没有Spring存在的意义。Spring提供了IoC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系。

  • 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。

Spring中Bean组件定义相关

  • Bean的定义 解析Bean的配置信息,封装到BeanDefinition中

  • Bean的创建 使用反射创建bean对象 id

  • Bean的解析 赋值、初始化等操作。

Spring Bean的创建是典型的工厂模式,它的顶级接口是BeanFactory。

职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

BeanFactory有三个子类:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。目的是为了区分Spring内部对象处理和转化的数据限制

但从图中可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。

Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象

BeanFactory,以Factory结尾,表示它是一个工厂(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是工厂的顶层接口,也是IOC容器的核心接口,因此BeanFactory中定义了管理Bean的通用方法,如 getBeancontainsBean 等.

BeanFactory只是个接口,并不是IOC容器的具体实现,所以Spring容器给出了很多种实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。

BeanFactory源码&使用情景

  • 从IOC容器中获取Bean(Name or Type)

  • 检索IOC容器中是否包含了指定的对象

  • 判断Bean是否为单例

public interface BeanFactory {
    
    /**
        对FactoryBean的转移定义,因为如果使用bean的名字来检索FactoryBean得到的是对象是工厂生成的对象,
        如果想得到工厂本身就需要转移
    */
    String FACTORY_BEAN_PREFIX = "&";

    //根据Bean的名字 获取IOC容器中对应的实例
    Object getBean(String var1) throws BeansException;
    
    //根据Bean的名字和class类型得到bean实例,增加了类型安全验证机制
    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    
   //查看Bean容器中是否存在对应的实例,存在返回true 否则返回false
    boolean containsBean(String var1);

    //根据Bean的名字 判断这个bean是不是单例
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    //得到bean实例的class类型
    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;    
    //得到bean的别名
    String[] getAliases(String var1);
}

Spring中的FactoryBean

FactoryBean是一个Bean,但又不仅仅是一个Bean,这样听起来矛盾,但为啥又这样说呢?其实在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂方法模式和装饰器模式类似

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
    getObject()方法: 会返回该FactoryBean生产的对象实例,我们需要实现该方法,以给出自己的对象实例化逻辑
    这个方法也是FactoryBean的核心.
    */
    @Nullable
    T getObject() throws Exception;

    /**
    getObjectType()方法: 仅返回getObject() 方法所返回的对象类型,如果预先无法确定,返回NULL,
    这个方法返回类型是在IOC容器中getBean所匹配的类型
    */
    @Nullable
    Class<?> getObjectType();

    //该方法的结果用于表明 工厂方法getObject() 所生产的 对象是否要以单例形式存储在容器中如果以单例存在就返回true,否则返回false
    default boolean isSingleton() {
        return true;
    }
}

为什么需要FactoryBean?

  • 在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。

  • 由于第三方库不能直接注册到spring容器,于是可以实现org.springframework.bean.factory.FactoryBean接口,然后给出自己对象的实例化代码即可。

FactoryBean的使用特点?

  • 当用户使用容器本身时,可以使用转义字符"&"来得到FactoryBean本身,以区别通过FactoryBean产生的实例对象和FactoryBean对象本身。

FactoryBean表现的是一个工厂的职责,如果一个BeanA 是实现FactoryBean接口,那么A就是变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()方法返回的对象,而不是对象本身,如果想获取工厂对象本身,需要在名称前面加上 '&'符号

  • getObject('name') 返回的是工厂中工厂方法生产的实例

  • getObject('&name') 返回的是工厂本身实例

使用场景

  • FactoryBean的最为经典的使用场景,就是用来创建AOP代理对象,这个对象在Spring中就是 ProxyFactoryBean

BeanFactory与FactoryBean区别

  • 他们两个都是工厂,但是FactoryBean本质还是一个Bean,也归BeanFactory管理

  • BeanFactory是Spring容器的顶层接口,FactoryBean更类似于用户自定义的工厂接口

BeanFactory和ApplicationContext的区别

  • BeanFactory是Spring容器的顶层接口,而ApplicationContext应用上下文类 他是BeanFactory的子类,他是Spring中更高级的容器,提供了更多的功能

    • 国际化

    • 访问资源

    • 载入多个上下文

    • 消息发送 响应机制

  • 两者的装载bean的时机不同

    • BeanFactory: 在系统启动的时候不会去实例化bean,只有从容器中拿bean的时候才会去实例化(懒加载)

      • 优点: 应用启动的时候占用的资源比较少,对资源的使用要求比较高的应用 ,比较有优势

    • ApplicationContext:在启动的时候就把所有的Bean全部实例化。

      • lazy-init= true 可以使bean延时实例化

      • 优点: 所有的Bean在启动的时候就加载,系统运行的速度快,还可以及时的发现系统中配置的问题。

Spring中观察者模式应用

观察者模式(发布-订阅(Publish/Subscribe)模式)它是用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应的作出反应。

在观察者模式中发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以应对多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

观察者和被观察者,是松耦合的关系;发布者和订阅者,则完全不存在耦合。

  • 在设计模式结构上,发布订阅模式继承自观察者模式,是观察者模式的一种实现的变体。

  • 在设计模式意图上,两者关注点不同,一个关心数据源,一个关心的是事件消息。

    • 观察者模式:数据源直接通知订阅者发生改变。

    • 发布订阅模式:数据源告诉第三方(事件通道)发生了改变,第三方再通知订阅者发生了改变。

Spring中观察者模式

Spring 基于观察者模式,实现了自身的事件机制也就是事件驱动模型,事件驱动模型通常也被理解成观察者或者发布/订阅模型。

Spring事件模型提供如下几个角色

  • 【事件】ApplicationEvent:是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。

    • ContextRefreshEvent,当ApplicationContext容器初始化完成或者被刷新的时候,就会发布该事件。

    • ContextStartedEvent,当ApplicationContext启动的时候发布事件.

    • ContextStoppedEvent,当ApplicationContext容器停止的时候发布事件.

    • RequestHandledEvent,只能用于DispatcherServlet的web应用,Spring处理用户请求结束后,系统会触发该事件。

  • 【事件监听】ApplicationListener:

    • ApplicationListener(应用程序事件监听器) 继承自jdk的EventListener,所有的监听器都要实现这个接口,这个接口只有一个onApplicationEvent()方法,该方法接受一个ApplicationEvent或其子类对象作为参数

    • 在方法体中,可以通过不同对Event类的判断来进行相应的处理.当事件触发时所有的监听器都会收到消息,如果你需要对监听器的接收顺序有要求,可是实现该接口的一个实现SmartApplicationListener,通过这个接口可以指定监听器接收事件的顺序。

    • 实现了ApplicationListener接口之后,需要实现方法onApplicationEvent(),在容器将所有的Bean都初始化完成之后,就会执行该方法。

  • 【事件源】ApplicationEventPublisher:事件的发布者,封装了事件发布功能方法接口,是Applicationcontext接口的超类

    • 事件机制的实现需要三个部分,事件源,事件,事件监听器,ApplicationEvent就相当于事件,ApplicationListener相当于事件监听器,ApplicationEventPublisher相当于时间源。

    • 我们常用的ApplicationContext都继承了AbstractApplicationContext,像我们平时常见ClassPathXmlApplicationContext、XmlWebApplicationContex也都是继承了它,AbstractApplicationcontext是ApplicationContext接口的抽象实现类,在该类中实现了publishEvent方法

  • 【事件管理】ApplicationEventMulticaster:用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。

    public interface ApplicationEventMulticaster {
        
        //添加事件监听器
        void addApplicationListener(ApplicationListener<?> var1);
    
        //添加事件监听器,使用容器中的bean
        void addApplicationListenerBean(String var1);
    
        //移除事件监听器
        void removeApplicationListener(ApplicationListener<?> var1);
    
        void removeApplicationListenerBean(String var1);
    
        //移除所有
        void removeAllListeners();
    
        //发布事件
        void multicastEvent(ApplicationEvent var1);
    
        void multicastEvent(ApplicationEvent var1, @Nullable ResolvableType var2);
    }
    // 在AbstractApplicationcontext中有一个applicationEventMulticaster
    // 的成员变量,
    // 提供了监听器Listener的注册方法
    public abstract class AbstractApplicationContext extends DefaultResourceLoader
            implements ConfigurableApplicationContext, DisposableBean {
    
      private ApplicationEventMulticaster applicationEventMulticaster;
        
      protected void registerListeners() {
            // Register statically specified listeners first.
            for (ApplicationListener<?> listener : getApplicationListeners()) {
                getApplicationEventMulticaster().addApplicationListener(listener);
            }
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let post-processors apply to them!
            String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
            for (String lisName : listenerBeanNames) {
                getApplicationEventMulticaster().addApplicationListenerBean(lisName);
            }
        }
    }

    事件机制工作流程

    监听器什么时候注册到IOC容器

    注册的开始逻辑是在AbstractApplicationContext类的refresh方法,该方法包含了整个IOC容器初始化所有方法。其中有一个registerListeners()方法就是注册系统监听者(Spring自带的)和自定义监听器的。

    public void refresh() throws BeansException, IllegalStateException {
        // BeanFactory准备工作完成后进行的后置处理工作
        this.postProcessBeanFactory(beanFactory);
    
        // 执行BeanFactoryPostProcessor的方法;
        this.invokeBeanFactoryPostProcessors(beanFactory);
    
        // 注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
        this.registerBeanPostProcessors(beanFactory);
    
        // 初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
        this.initMessageSource();
    
        // 初始化事件派发器
        this.initApplicationEventMulticaster();
    
        // 子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器
        this.onRefresh();
    
        // 注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean,这些监听器是注册到ApplicationEventMulticaster中的
        this.registerListeners();
    
        // 初始化所有剩下的非懒加载的单例bean
        this.finishBeanFactoryInitialization(beanFactory);
    
        // 完成context的刷新
        this.finishRefresh();
        }

    看registerListeners的关键方法体,其中的两个方法addApplicationListener和addApplicationListenerBean,从方法可以看出是添加监听者。

    protected void registerListeners() {
        Iterator var1 = this.getApplicationListeners().iterator();
    
        while(var1.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var1.next();
            this.getApplicationEventMulticaster().addApplicationListener(listener);
        }
    
        String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = listenerBeanNames;
        int var3 = listenerBeanNames.length;
    
        for(int var4 = 0; var4 < var3; ++var4) {
            String listenerBeanName = var7[var4];
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }
    }

    该接口主要两个职责,维护ApplicationListener相关类和发布事件。实现在默认实现类AbstractApplicationEventMulticaster,最后将Listener放到了内部类ListenerRetriever两个set集合中

    private class ListenerRetriever {
            public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet();
            public final Set<String> applicationListenerBeans = new LinkedHashSet();
    }

    ListenerRetriever被称为监听器注册表。

    Spring如何发布的事件并通知监听者

    这个注意的有两个方法

    publishEvent方法

    • AbstractApplicationContext实现了ApplicationEventPublisher 接口的publishEvent方法

     
    
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        
        //尝试转换为ApplicationEvent或者PayloadApplicationEvent,如果是PayloadApplicationEvent则获取eventType
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }
    
       
        if (this.earlyApplicationEvents != null) {
             //判断earlyApplicationEvents是否为空(也就是早期事件还没有被发布-说明广播器还没有实例化好),如果不为空则将当前事件放入集合
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            //否则获取ApplicationEventMulticaster调用其multicastEvent将事件广播出去。本文这里获取到的广播器实例是SimpleApplicationEventMulticaster。
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }
            
        //将事件交给父类处理
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }
    
    }

    multicastEvent方法继续进入到multicastEvent方法,该方法有两种方式调用invokeListener,通过线程池和直接调用,进一步说就是通过异步和同步两种方式调用.

    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        
        //解析事件类型
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        
        //获取执行器
        Executor executor = this.getTaskExecutor();
        
        // 获取合适的ApplicationListener,循环调用监听器的onApplicationEvent方法
        Iterator var5 = this.getApplicationListeners(event, type).iterator();
    
        while(var5.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var5.next();
            if (executor != null) {
                //如果executor不为null,则交给executor去调用监听器
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                //否则,使用当前主线程直接调用监听器;
                this.invokeListener(listener, event);
            }
        }
    
    }

    invokeListener方法

    // 该方法增加了错误处理逻辑,然后调用doInvokeListener
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }
    
    }
    
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        //直接调用了listener接口的onApplicationEvent方法
        listener.onApplicationEvent(event);  
    }

    相关文章:

  • 【零基础玩转多模态AI:Gemma3 27B开源视觉模型本地部署与远程访问】
  • 全星APQP软件:为用户提供高效、合规、便捷的研发管理体验
  • HDLBIT知识点
  • 探索 Vue 3 响应式系统:原理与实践
  • 蓝桥杯电子赛_E2PROM(AT24C02)
  • Agent 2 Agent VS MCP
  • 【C++】深拷贝与浅拷贝
  • GitHub 趋势日报 (2025年04月08日)
  • C语言精讲-12
  • 【Linux】基础开发工具
  • 八大可商用桌面客户端应用开发框架深度指南-优雅草卓伊凡
  • 操作系统基础:05 系统调用实现
  • playwright 教程高级篇:掌握网页自动化与验证码处理等关键技术详解
  • [数据结构]排序 --2
  • 【C++】C++的引用
  • 在 Ubuntu 下通过 Docker 部署 Caddy 服务器
  • C++双链表介绍及实现
  • 从输入URL到页面渲染:浏览器请求的完整旅程解析
  • LLM学习笔记3——使用Docker(vLLM+OpenWebUI)实现本地部署DeepSeek-R1-32B模型
  • 基于HASM模型的高精度建模matlab仿真
  • 巴基斯坦外长:近期军事回应是自卫措施
  • 深圳市政协原副主席王幼鹏被“双开”
  • 习近平会见古共中央第一书记、古巴国家主席迪亚斯-卡内尔
  • 14岁女生瞒报年龄文身后洗不掉,法院判店铺承担六成责任
  • 无人机穿越大理千年古塔落券洞内,涉事“飞手”被行拘10日
  • 金融监管总局:近五年民企贷款投放年平均增速比各项贷款平均增速高出1.1个百分点