首页 > 编程语言 >Spring源码理解 类接口说明

Spring源码理解 类接口说明

时间:2024-10-11 22:49:33浏览次数:8  
标签:初始化 Object 实例 Spring beanName 接口 Bean 源码 方法

FactoryBean、BeanFactory

BeanFactory

BeanFactory是管理和生产Bean的,它是用于访问Spring Bean容器的根接口。,定义了管理Bean的方法,获取Bean、包含Bean、是否单例Bean、获取Bean类型等。Spring根据他提供了很多实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等。其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。AnnotationConfigApplicationContext类是基于组件类作为输入的Spring上下文入口,比如@Configuration注解标注的类和@ComponentScan标注的类

FactorBean

FactoryBean首先是一个Bean,其次他能生产Bean,它是某个Bean的工厂类,主要用于生产这个Bean

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean。至于为什么会有FactoryBean?

  1. 实例化Bean比较复杂,单纯使用反射受限,使用FactoryBean专门来创建具体的Bean。实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑
  2. 由于第三方库不能直接注册到spring容器,于是可以实现org.springframework.bean.factory.FactoryBean接口,然后给出自己对象的实例化代码即可

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

  • getObject(’ name ')返回工厂中的实例
  • getObject(’ &name ')返回工厂本身的实例
源码

在refresh方法的finishBeanFactoryInitialization中,是为其他还没有实例化的Bean进行实例化。preInstantiateSingletons方法来实例化单例对象。在初始化Bean实例获取Bean的时候,会判断当前BeanDefinition当前的beanName是不是FactoryBean,如果是,则会先获取FactoryBean的实例。如果该工厂Bean实现了SmartFactoryBean(一般Spring框架内部使用),则会立刻初始化工厂Bean指向的Bean。

FactoryBean——Spring的扩展点之一 - 掘金 (juejin.cn)

Bean生命周期

  1. 根据Bean定义创建Bean的对象
  2. Bean对象创建完后,设置属性值的注入
  3. 为当前Bean调用所有BeanPostProcessor后置处理器的初始化前的方法,此时会设置ApplicationContextAware等各种Aware
  4. 调用初始化方法,比如InitializingBean接口的afterPropertiesSet方法,或者配置了initMethod方法
  5. 为当前Bean调用所有BeanPostProcessor后置处理器的初始化后的方法
  6. Bean添加到单例线程池中,被容器管理
  7. Bean实现了DisposableBean接口,执行destory方法或调用了声明destory-method的方法

Bean创建过程

test方法----…---->refresh()
---->finishBeanFactoryInitialization()
.
---->preInstantiateSingletons()
.
---->preInstantiateSingletons()
.
---->getBean()
.
---->doGetBean()
.
----> getSingleton(beanName, new ObjectFactory()
这是一个简单的流程,可以大致看一下在容器启动的时候具体调用了哪些方法;

我们先进入doGetBean方法里面:发现其实是调用了getSingleton方法获取实例,
如果没有获取到又通过getObject()里面的 createBean(beanName, mbd, args)创建实例,总之这个实例一定要创建出来

Bean创建循环依赖

Bean在创建过程中会把自己暴露出来。一个是初始化对象之后会提前暴露处来,添加到单例工厂集合中,Bean完全实例化创建后会添加到单例对象集合中,删除单例工厂集合和暴露对象集合。暴露出来后,其他Bean就可以获取这个Bean的实例。

而在当前Bean如果依赖其他没有实例化Bean的时候,也就是@Autowire注解标注了一个没有实例化的属性。这时会在Bean初始化Bean之前(后置处理器初始化前,初始化方法,后置处理器初始化后),进行属性注入,也就是populateBean(beanName, mbd, instanceWrapper)方法。其内部会有后置处理器AutowiredAnnotationBeanPostProcessor来处理,检查到标注的@Autowired属性B,获取他的Bean。如果它也依赖了A,就形成了循环依赖。

如果A注入了B,B中注入了A。那么会先初始化A,暴露单例工厂自身A,注入属性的时候检查到标注了自动注入注解,则会初始化B,暴露单例工厂自身B,B进行注入属性的时候检查到依赖了A,这个时候获取A的Bean就可以走循环依赖的三级缓存,从单例工厂中获取A的Bean,并添加到暴露单例对象中。当B的Bean创建完毕后,就完成A的Bean的属性注入了,就正常创建A的。Bean创建完之后会添加到singletonObjects中,后续直接获取。

为什么需要三级缓存,通过单例工厂来创建提前Bean?

首先他俩在内存中是同一个对象,其次是为了解决AOP切面代理问题。

getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象,如果未被代理则返回的是原bean实例

源码

bean的获取最先是从AbstractBeanFactory.doGetBean方法中开始。第一步就是直接获取单例对象,也就是从三级缓存(三个Map)中获取,Object sharedInstance = getSingleton(beanName);。主要是获取共享的单例Bean,也就是说共享暴露出来的。首先会从单例Bean集合(singletonObjects)中获取,获取不到就从早期暴露出Bean的集合(earlySingletonObjects)中获取,然后是从提前暴露的工厂对象中(singletonFactories)获取。如果在Bean实例集合或者提早暴露的中能获取的直接返回实例,否则看实例工厂有没有,有了就获取对象实例,并添加到暴露集合中。如果没有,最后就是空的。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            synchronized (this.singletonObjects) {
                // Consistent creation of early reference within full singleton lock
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

如果Bean取不到就会创建Bean

创建Bean,如果有父容器则由父容器来创建Bean,没有了,则才会用当前子容器创建Bean。

获取Bean定义,判断是否有依赖的Bean,依赖的Bean有没有创建,如果没有创建就先创建依赖Bean,也是进入这个方法中创建Bean。dependentBeanMap中定义依赖的Bean集合

依赖Bean创建完之后会创建当前Bean。创建Bean会判断是单例的,原型的,获取其他的。进入单例的判断,创建Bean就是执行的createBean方法中创建的。

// 重载方法,第二次获取单例Bean,实际上根据createBean(beanName, mbd, args);创建
sharedInstance = getSingleton(beanName, () -> {
    try {
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // Explicitly remove instance from singleton cache: It might have been put there
        // eagerly by the creation process, to allow for circular reference resolution.
        // Also remove any beans that received a temporary reference to the bean.
        destroySingleton(beanName);
        throw ex;
    }
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

实际创建Bean的方法

内部调用Object beanInstance = doCreateBean(beanName, mbdToUse, args);在AbstractAutowireCapableBeanFactory类中,以下是实际创建Bean的方法签名。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

首先会根据反射或动态代理创建一个对象,将创建出来的对象构建成单例工厂,添加到三级缓存中。也就是单例工厂集合中,主要用于提前暴露自身。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    // 三级缓存那块的三个集合,添加了提早暴露Bean Map earlySingletonObjects,单例工厂singletonFactories
    // SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

然后会进行属性注入,也就是自动依赖注入,@Value、@Autowired的处理,如果有依赖对象,则会创建依赖的Bean。相当于又重新走了一遍创建Bean,如果这个时候发现了要注入的Bean依赖了A,就获取A这个Bean,那么A这个Bean就可以从三级缓存方法中获取。

后面,属性注入完成后,就初始化Bean的操作了。Bean初始化完成之后,就把Bean加入到一级缓存中了。后面直接从一级缓存中获取完成的Bean实例

BeanFactoryPostProcessor BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor是在发生在bean实例化之前,BeanDefinition读取完之后。所以我们在这里可以获取到BeanDefinition,以改变他默认的实例化方式。

BeanDefinitionRegistryPostProcessor可以注册BeanDefinition。不但可以完全控制是否加入某个bean,动态加入某些bean,并且还可以控制bean的生成过程,比如像其直接注入属性等操作

实现逻辑和位置

AbstractApplicationContext类的invokeBeanFactoryPostProcessors方法就是处理实现了这两个后置处理器的类的,方法里会获取扫描到的类,并回调实现的方法。

BeanDefinitionRegistryPostProcessor扩展和BeanFactoryPostProcessor是在同一时间节点进行回调的,并且他的优先级是高于BeanFactoryPostProcessor,而他的作用是像spring容器中注册BeanDefinition。

首先是实现BeanDefinitionRegistryPostProcessor的类,会优先回调实现了PriorityOrdered接口的,然后进行排序再执行回调。然后是实现了Ordered接口的,然后排序后在执行回调,最后是其他的实现类,也会进行排序一下再执行回调。这里是直接回调postProcessBeanDefinitionRegistry方法了。等所有的都执行完了,才会统一回调postProcessBeanFactory方法。

随后才会获取实现BeanFactoryPostProcessor的类,依据顺序规则进行回调。

实现类

ApplicationContextAware ApplicationContextAwareProcessor

ApplicationContextAware接口主要用来注入容器实例的,就是ApplicationContext上下文的。

实现这个接口的类都可以通过,重写setApplicationContext方法得到参数列表上的ApplicationContext对象。

ApplicationContextAwareProcessor类是设置ApplicationContext对象的关键。他实现了BeanPostProcessor接口,重写方法postProcessBeforeInitialization里实现了其他的Spring内部对象,包括以下Aware接口。在实例化Bean(initializeBean)的时候都会执行BeanPostProcessor的操作

  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ResourceLoaderAware
  • ApplicationEventPublisherAware
  • MessageSourceAware
  • ApplicationContextAware
  • ApplicationStartupAware

在Bean初始化后调用的AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization方法里会查询全部的BeanPostProcessor实例,然后依次将当前Bean和BeanName传入执行postProcessBeforeInitialization方法。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    invokeAwareMethods(beanName, bean);

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行所有BeanPostProcessor的postProcessBeforeInitialization方法
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行所有BeanPostProcessor的postProcessAfterInitialization方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

BeanPostProcessor

后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    invokeAwareMethods(beanName, bean);

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行postProcessBeforeInitialization
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行postProcessAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

所有实现了BeanPostProcessor的实现类都会在每个Bean初始化的时候执行一遍。因此内部很多实现了该接口的类都会判断一下当前Bean是不是某种类型的Bean,才会执行相关操作。例如ApplicationContextAwareProcessor

子类:

  • InitDestroyAnnotationBeanPostProcessor 处理初始化方法(我们初始化方法是如何执行的,如何被容器发现的,都是因为这个组件在工作,可在int-method打断点看看具体调试)
  • AutowiredAnnotationBeanPostProcessor 处理自动装配
  • BeanValidationPostProcessor
  • ApplicationContextAwareProcessor

SmartInitializingSingleton InitializingBean

SmartInitializingSingleton

在 Spring 容器中所有单例 Bean 初始化完成后执行一些自定义的初始化逻辑。当所有单例 Bean 的依赖关系都解析完毕,并且所有单例 Bean 的实例化与初始化过程完成后,Spring 容器会自动回调 SmartInitializingSingleton 接口的实现类的 afterSingletonsInstantiated() 方法。可以在该方法中编写自己的初始化逻辑。注意,这个方法只会被调用一次。

SmartInitializingSingleton 接口的使用场景通常是在所有单例 Bean 初始化完成后,希望执行一些需要考虑所有 Bean 依赖关系的初始化逻辑,例如进行缓存预热、启动一些定时任务等操作。

preInstantiateSingletons

// 为所有单例非懒加载的Bean触发初始化后回调...调用SmartInitializingSingleton接口的afterSingletonsInstantiated方法
for (String beanName : beanNames) {
    Object singletonInstance = getSingleton(beanName);
    if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
        StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
                .tag("beanName", beanName);
        smartSingleton.afterSingletonsInstantiated();
        smartInitialize.end();
    }
}

事件机制

事件类型

  • ApplicationEvent 事件抽象类

  • ApplicationContextEvent 用于应用程序上下文的事件的基类

  • ContextStoppedEvent 当应用程序上下文停止时引发的事件

  • ContextRefreshedEvent 在ApplicationContext被初始化或刷新时引发的事件

  • ContextStartedEvent 当应用程序上下文启动时引发的事件

  • ContextClosedEvent 当应用程序上下文关闭时引发的事件

发布订阅,事件组播器

  • ApplicationEventMulticaster 接口由可以管理多个ApplicationListener对象的对象实现,并向它们发布事件

  • AbstractApplicationEventMulticaster 提供基本的侦听器注册功能

  • SimpleApplicationEventMulticaster 提供基本的侦听器注册功能,忽略它不感兴趣的事件

  • org.springframework.context.ApplicationEventPublisherAware 任何对象希望被其运行的ApplicationEventPublisher(通常是ApplicationContext)通知的任何对象实现的接口

  • EventPublicationInterceptor 事件发布拦截器

  • ApplicationEventPublisher 封装事件发布功能的接口

监听器

  • ApplicationListener
  • GenericApplicationListener
  • ApplicationListenerMethodAdapter

源码

初始化组播器

组播器收集所有监听器,并在接收到事件响应后匹配对应的监听器进行处理。

refresh方法中的initApplicationEventMulticaster方法会初始化事件组播器。首先会从BeanFactory中找是否已经有自定义的id为applicationEventMulticaster的Bean,有的话把它作为事件组播器。否则就初始化一个类型为SimpleApplicationEventMulticaster的

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                    "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

注册监听器

refresh()方法的registerListeners()方法中,用于注册所有监听器。

找到所有实现了ApplicationListener接口的监听器类,并将其Bean名称添加到ApplicationEventMulticaster组播器实例的applicationListenerBeans集合中。

protected void registerListeners() {
    // 注册 已在容器中的(this.applicationListeners里的) 且已被初始化的ApplicationListener
    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 listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 发布早期应用程序事件,现在我们终于有了多路广播...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

EventListenerMethodProcessor处理标注EventListener注解的方法为监听器并注册

EventListenerMethodProcessor类是查找监听器的,它实现了BeanFactoryPostProcessor和SmartInitializingSingleton来做这件事。这个类的Bean名为org.springframework.context.event.internalEventListenerProcessor,最初源自AnnotationConfigUtils.registerAnnotationConfigProcessors。他在代码第一行new上下文的时候的构造函数里就已经加到BeanDefinition中了。

因为实现了BeanFactoryPostProcessor,所以它早在invokeBeanFactoryPostProcessors的时候就已经创建了Bean。然后在refresh()中的finishBeanFactoryInitialization()中才开始执行afterSingletonsInstantiated()方法。

processBean()方法中具体处理了相关内容。扫描到有标注EventListener注解的类,根据目标类Class,方法Method和Bean名称,使用事件监听工厂创建监听器对象。并将其添加到SpringContext上下文的监听器列表和ApplicationEventMulticaster组播器中的集合中

// 有方法标注了,则根据监听所在方法注册成监听器对象,添加到组播器中
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
// 获取默认的监听器工厂
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
// 循环多个监听方法和多个监听器工厂,根据不同的监听器工厂创建多个监听器对象
for (Method method : annotatedMethods.keySet()) {
    for (EventListenerFactory factory : factories) {
        // 根据监听器工厂判断被监听非方法是否满足要求
        if (factory.supportsMethod(method)) {
            // 把这个方法转为一个可以执行的方法(主要和访问权限有关)
            Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
            // 根据监听器工厂创建监听器实例
            ApplicationListener<?> applicationListener =
                    factory.createApplicationListener(beanName, targetType, methodToUse);
            // 如果是ApplicationListenerMethodAdapter实例,则进行初始化。默认工厂DefaultEventListenerFactory创建的就是这个实例
            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
            }
            // 将监听器实例添加到spring上下,同时会添加到组播器中
            context.addApplicationListener(applicationListener);
            break;
        }
    }
}

发布事件

context.publishEvent(new AddEvent("-123"));

其中 invokeListener 方法中就调用了ApplicationEvent的onApplicationEvent方法了。

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    // 将推送的参数转换为ApplicationEvent
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent applEvent) {
        applicationEvent = applEvent;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event, eventType);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        // 执行事件的推送操作
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // 如果当前容器有父容器,则也会调用父容器的事件推送
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext abstractApplicationContext) {
            abstractApplicationContext.publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

在循环监听器中获取监听器列表方法使用了缓存的功能getApplicationListeners(event, type)

【Spring源码】事件监听机制全解_spring事件监听获取返回值-CSDN博客

动态注册Bean

可根据注解的方式,动态注入bean,而不需要显式根据Componment等注解。一般都是第三方库采用这种方式,比如Mybatis,使用的MapperScannerRegistrar类,对应的依赖注解就是@MapperScan。

使用ImportBeanDefinitionRegistrar接口可以实现,一般结合@Import注解和@Configuration注解。所有实现了该接口的类的都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先与依赖其的bean初始化的,也能被aop、validator等机制处理。

动态注册Bean,其目的就是将扫描到的Bean添加到BeanFactory实例 IOC容器中,一般添加为单例Bean。

示例

以类似OpenFeign的Http调用的方式的示例来使用这个。实现细节为定义一个接口类为Http接口集合,每个方法为请求方法,根据请求注解配置相关请求地址等属性进行远程调用。即将接口类注入到Ioc容器中,依据动态代理的方式代理接口类,代理类处理每个方法进行业务处理。

而当前实现动态注册Bean只是将在Http接口集合所在的类注册Bean,通过注解扫描的方式动态注册。

我们需要定义如下类:

  • 定义类似@MapperScan注解的开关扫描注解, EnableHttpUtil.java
  • 定义的MapperScan注解中引入的MapperScannerRegistrar类,也就是实现ImportBeanDefinitionRegistrar接口类,此处为 HttpBeanRegistrar.java
  • 定义@HttpUtil注解,被该注解标注的类就是需要动态注册的Bean。当然也可以不扫描被该注解标注的,只要是根据扫描配置类扫描到就行。
  • 以上其实就可以完成动态注册Bean了。但实际注册Bean之后,后续还要处理更多的业务。比如扫描到Mapper接口类的方法可以直接调用。
  • 接下来类似OpenFeign的方式,定义方法上的调用注解HttpRequest.java
  • 业务处理类,发送http请求类 DemoHttpHandler.java
  • 定义某个被扫描业务使用接口, IRequestDemo.java
注解类
// 开关扫描类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(HttpBeanRegistrar.class)
public @interface EnableHttpUtil {
}
// 请求方法类型枚举
public enum HTTPMethod {
	GET,POST,PUT,DELETE
}
// 请求方法注解,标注在方法上
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HttpRequest {
	HTTPMethod httpMethod() default HTTPMethod.GET;
	String url();
}
// Http工具类,标注在类上,类似FeignClient
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface HttpUtil {
}

HttpBeanRegistrar
/**
 * 动态Bean注入类,在ConfigurationClassPostProcessor中会被处理到
 */
public class HttpBeanRegistrar implements ImportBeanDefinitionRegistrar,
        ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, BeanClassLoaderAware {


    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        registerHttpRequest(registry);
    }

    /**
     * 动态注册Bean方法
     *
     * @param registry
     */
    private void registerHttpRequest(BeanDefinitionRegistry registry) {
        // 构建扫描类
        ClassPathScanningCandidateComponentProvider classPathBeanDefinitionScanner = getClassScanner();
        classPathBeanDefinitionScanner.setResourceLoader(this.resourceLoader);
        // 设置只扫描HttpUtil注解的类
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(HttpUtil.class);
        classPathBeanDefinitionScanner.addIncludeFilter(annotationTypeFilter);
        // 定义扫描包
        String basePackage = "com.cgq.dynamicbean";
        Set<BeanDefinition> candidateComponents = classPathBeanDefinitionScanner.findCandidateComponents(basePackage);
        for (BeanDefinition beanDefinition : candidateComponents) {
            if (beanDefinition instanceof AnnotatedBeanDefinition) {
                registerBeans(((AnnotatedBeanDefinition) beanDefinition));
            }
        }

    }

    /**
     * 构造Class扫描器,设置了只扫描顶级接口,不扫描内部类
     *
     * @return
     */
    private ClassPathScanningCandidateComponentProvider getClassScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {

            @Override
            protected boolean isCandidateComponent(
                    AnnotatedBeanDefinition beanDefinition) {
                if (beanDefinition.getMetadata().isInterface()) {
                    try {
                        Class<?> target = ClassUtils.forName(
                                beanDefinition.getMetadata().getClassName(),
                                classLoader);
                        return !target.isAnnotation();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                return false;
            }
        };
    }

    /**
     * 注册Bean方法,根据Bean定义对象获取Bean的类型,并创建该对象的代理
     *
     * @param beanDefinition
     */
    private void registerBeans(AnnotatedBeanDefinition beanDefinition) {
        String className = beanDefinition.getBeanClassName();
        ((DefaultListableBeanFactory) this.beanFactory).registerSingleton(className, createProxy(beanDefinition));
    }

    /**
     * 创建代理类,内部处理请求Http的逻辑
     *
     * @param beanDefinition
     * @return
     */
    private Object createProxy(AnnotatedBeanDefinition beanDefinition) {
        try {
            AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
            Class<?> target = Class.forName(annotationMetadata.getClassName());
            InvocationHandler invocationHandler = createInvocationHandler();
            Object proxy = Proxy.newProxyInstance(HttpRequest.class.getClassLoader(), new Class[]{target}, invocationHandler);
            return proxy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private InvocationHandler createInvocationHandler() {

        return new InvocationHandler() {
            private DemoHttpHandler demoHttpHandler = new DemoHttpHandler();

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                return demoHttpHandler.handle(method);
            }
        };
    }

    private ResourceLoader resourceLoader;

    private BeanFactory beanFactory;

    private ClassLoader classLoader;
    private Environment environment;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
DemoHttpHandler
/**
 * 定义业务处理类来处理注解标注的地址,并进行真实的http请求
 */
public class DemoHttpHandler {
	/**
	 * 实际业务调用处理
	 * @param method
	 * @return
	 */
	public HttpResult<?> handle(Method method) {
		HttpRequest request = method.getAnnotation(HttpRequest.class);
		String url = request.url();
		String methodName = request.httpMethod().name();
		String str = String.format("http request: url=%s and method=%s", url, methodName);
		return new HttpResult<String>(str, 200);
	}
}
IRequestDemo
@HttpUtil
public interface IRequestDemo {
	//调用test1时,会对http://abc.com发送get请求
	@HttpRequest(url = "http://abc.com")
	HttpResult<String> test1();
	//调用test2时,会对http://test2.com发送post请求
	@HttpRequest(url = "http://test2.com")
	HttpResult<String> test2();
}

HttpResult
public class HttpResult<T> {

	private String result;
	private int status;

	public HttpResult() {
	}

	public HttpResult(String result, int status) {
		this.result = result;
		this.status = status;
	}

	@Override
	public String toString() {
		return "HttpResult{" +
				"result='" + result + '\'' +
				", status=" + status +
				'}';
	}
}
Application
@EnableHttpUtil
@SpringBootApplication
public class DynamicBeanImportApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DynamicBeanImportApplication.class, args);

        IRequestDemo bean = run.getBean(IRequestDemo.class);
        HttpResult<String> stringHttpResult = bean.test1();
        System.out.println(stringHttpResult);
    }
}

动态注册bean,Spring官方套路:使用ImportBeanDefinitionRegistrar - 知乎 (zhihu.com)

依赖注入 DI 控制反转Ioc

控制反转和依赖注入的理解(通俗易懂)-CSDN博客

Ioc

Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;*谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)*
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序

DI

组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。**依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。**通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

总结

IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。

标签:初始化,Object,实例,Spring,beanName,接口,Bean,源码,方法
From: https://blog.csdn.net/qq_34656606/article/details/142865168

相关文章

  • centos7.6源码方式安装python3.6.8
    1安装依赖包centos7.6是没有自带python3的[root@opgs201~]#cat/etc/redhat-releaseCentOSLinuxrelease7.6.1810(Core)[root@opgs201~]#python3bash:python3:commandnotfound...Similarcommandis:'python'先挂载iso文件,配置本地yum源##挂载虚拟机的光盘......
  • springboot+vue基于Web的辅助教学平台【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和普及,教育领域正经历着深刻的变革。传统的教学方式逐渐难以满足现代学生的学习需求,他们渴望更加灵活、便捷的学习方式。与此同时,教师也面临教学资源分配不均、管理效率低下等问题。因此,开发一个基于Web的辅......
  • springboot+vue基于springboot+vue的线上学习系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着互联网技术的迅猛发展和信息技术的不断革新,线上学习系统逐渐成为教育领域的重要组成部分。近年来,受疫情影响,线上学习需求更是急剧增长,为教育领域带来了前所未有的挑战与机遇。传统的线下教学模式已经难以满足现代教育的多元化需求......
  • springboot+vue基于Springboot校园招聘系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景在当今信息化高速发展的时代,校园招聘已成为企业与高校毕业生双向选择的重要渠道。然而,传统的校园招聘方式存在信息不对称、流程繁琐、效率低下等问题,严重制约了招聘双方的沟通与选择。随着互联网的普及和大数据技术的应用,构建一个高效......
  • springboot+vue+java高中素质评价档案系统ssm
    目录功能和技术介绍系统实现截图技术范围开发核心技术介绍:代码执行流程核心代码部分展示系统测试其他springboot项目推荐详细视频演示源码获取功能和技术介绍探索如何设计一个用户友好、响应迅速的系统界面,确保系统后端逻辑的高效和稳定性。研究如何通过SpringBoot......
  • 计算机毕业设计 基于Django的学生选课系统的设计与实现 Python+Django+Vue 前后端分离
    ......
  • 毕设项目案例实战II基于Java+Spring Boot+MySQL的学生选课系统的设计与实现(源码+数据
    目录一、前言二、技术介绍三、系统实现四、论文参考五、核心代码六、源码获取全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末一、前言随着信息技术的飞速发展和教育信息化的不......
  • 毕设项目案例实战II基于SSM的健身房预约系统设计与实现(源码+数据库+文档)
    目录一、前言二、技术介绍三、系统实现四、论文参考五、核心代码六、源码获取全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末一、前言随着健康意识的日益增强,健身房已成为现代......
  • 基于SpringBoot+Vue+uniapp的税务门户网站的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • SpringMVC静态资源处理
    基本使用@ComponentpublicclassWebMvcConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){registry.addResourceHandler("/asset/**").addResourceLocations(&qu......