• Spring 中有哪些感知接口



    前言:     最近工作中正好使用的感知接口, 简单整理相关的知识。因为感知接口有哪些Spring框架是如何实现的也是常见的面试问题


    目录

    1.Spring Aware

    2.Spring常用感知接口

    2.1BeanClassLoaderAware接口

    2.2ApplicationContextAware接口

    2.3BeanFactoryAware接口

    2.4BeanNameAware接口

    2.5MessageSourceAware接口

    2.6ApplicationEventPublisherAware接口

    2.7ResourceLoaderAware接口

    3.感知接口如何实现回调

    4.自测试用例


          Spring内置了用于不同目的的大量感知接口,例如:实例BeanFactoryAware的Bean在初始后,Spring容器将会注入BeanFactory的实例,而实例ApplicationContextAware的Bean,在Bean被初始后,将会被注入 ApplicationContext的实例等等。

    1.Spring Aware

    Spring Aware的目的就是为了让Bean获得Spring容器的服务,感知接口都继承Aware接口。Aware接口中没有实现方法,它只是一个标记超接口。它表明实现此接口的Spring容器中的bean ,在初始化时候可以实现某个回调样方法,实际回调的的方法签名由各个子接口确定

    1. package org.springframework.beans.factory
    2. public interface Aware {
    3. //标记接口
    4. }

    2.Spring常用感知接口

    2.1BeanClassLoaderAware接口

    该接口回调接口将ClassLoader对象注入到时受管Bean的实例中可让受管Bean本身知道它是由哪一类装载器负责装载的

    1. public interface BeanClassLoaderAware extends Aware {
    2. void setBeanClassLoader(ClassLoader classLoader);
    3. }

    2.2ApplicationContextAware接口

     该接口将对象ApplicationContextAware对象注入到当前受管Bean实例中,这样受管Bean能够感知到IoC容器的存在并得到相应的支持

    1. public interface ApplicationContextAware extends Aware {
    2. /**
    3. *设置运行此对象的ApplicationContext。通常此调用将用于初始化对象。
    4. *在填充普通bean属性之后但在初始化回调之前调用
    5. */
    6. void setApplicationContext(ApplicationContext applicationContext)
    7. throws BeansException;
    8. }

    2.3BeanFactoryAware接口

    该接口将对象BeanFactory对象注入到受管Bean实例中,

    1. public interface BeanFactoryAware extends Aware {
    2. /*
    3. *向bean实例提供所属工厂的回调。
    4. *在填充正常bean属性后调用但在初始化回调之前
    5. */
    6. void setBeanFactory(BeanFactory beanFactory) throws BeansException;
    7. }

    2.4BeanNameAware接口

    该接口将Bean本身的id(name)对象注入到受管Bean实例中,

    1. public interface BeanNameAware extends Aware {
    2. /*
    3. *在创建此bean的bean工厂中设置bean的名称。
    4. *在填充普通bean属性之后但在初始化之前调用
    5. *类似InitializingBean的afterPropertiesSet或自定义init方法的回调
    6. */
    7. void setBeanName(String name);
    8. }

    2.5MessageSourceAware接口

    该接口负责将MessageSource对象注入到当前受管Bean实例中,这样受管Bean能够获得国际化和本地化消息的支持

    1. //请注意,MessageSource通常也可以作为bean传递引用(任意bean属性或构造函数参数)
    2. //因为它在应用程序上下文中定义为名为“messageSource”的bean
    3. public interface MessageSourceAware extends Aware {
    4. /*
    5. *设置运行此对象的MessageSource。
    6. *在填充普通bean属性之后但在初始化之前调用
    7. */
    8. void setMessageSource(MessageSource messageSource);
    9. }

    2.6ApplicationEventPublisherAware接口

    该接口将ApplicationEventPublisher对象注入到当前受管Bean实例中,这样受理的Bean能够获得分发事件的支持

    1. public interface ApplicationEventPublisherAware extends Aware {
    2. /*
    3. *设置运行此对象的ApplicationEventPublisher
    4. *在填充普通bean属性之后但在初始化之前调用
    5. *此对象要使用的@param applicationEventPublisher事件发布器
    6. */
    7. void setApplicationEventPublisher(ApplicationEventPublisher
    8. applicationEventPublisher);
    9. }

    2.7ResourceLoaderAware接口

    该接口接口负责将ResourceLoader对象注入到当前的受管Bean实例中,这样受管Bean能够得到获取资源的支持

    1. public interface ResourceLoaderAware extends Aware {
    2. /*
    3. * 设置运行此对象的ResourceLoader
    4. */
    5. void setResourceLoader(ResourceLoader resourceLoader);
    6. }

    3.感知接口如何实现回调

    先看下实例化bean对象的过程,大致如下图,随着Spring版本提升细节虽然有变化但是大致流程相同。 

     (图片来自网络)

    给BEAN实例注入所需资源是在后置处理阶段发生, ApplicationContextAwareProcessor 实现接口BeanPostProcessor ,在初始化之前调用invokeAwareInterfaces方法实现将受管BEAN所需要的资源注入到BEAN对象中

    源代码如下:

    1. class ApplicationContextAwareProcessor implements BeanPostProcessor {
    2. //代码略
    3. //接口BeanPostProcessor的方法实现
    4. //在实例化及依赖注入完成后、在任何初始化代码(比如配置文件中的init-method)调用之前调用
    5. @Override
    6. @Nullable
    7. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    8. if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
    9. bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
    10. bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
    11. bean instanceof ApplicationStartupAware)) {
    12. return bean;
    13. }
    14. AccessControlContext acc = null;
    15. if (System.getSecurityManager() != null) {
    16. acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    17. }
    18. if (acc != null) {
    19. AccessController.doPrivileged((PrivilegedAction) () -> {
    20. invokeAwareInterfaces(bean);
    21. return null;
    22. }, acc);
    23. }
    24. else {
    25. invokeAwareInterfaces(bean);
    26. }
    27. return bean;
    28. }
    29. // 实例化BEAN初始化之前,将所需的资源注入到BEAN中
    30. private void invokeAwareInterfaces(Object bean) {
    31. if (bean instanceof EnvironmentAware) {
    32. ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    33. }
    34. if (bean instanceof EmbeddedValueResolverAware) {
    35. ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    36. }
    37. if (bean instanceof ResourceLoaderAware) {
    38. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    39. }
    40. if (bean instanceof ApplicationEventPublisherAware) {
    41. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    42. }
    43. if (bean instanceof MessageSourceAware) {
    44. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    45. }
    46. if (bean instanceof ApplicationStartupAware) {
    47. ((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
    48. }
    49. if (bean instanceof ApplicationContextAware) {
    50. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    51. }
    52. }
    53. }
    54. 综上所述,实现感知接口Aware的Bean在被初始之后,DI容器就会自动调用这些回调接口所定义的方法,进而将相关对象注入进来,以取得所需的资源。

      4.自测试用例

      创建一个SpringBoot工程,但是本用例不使用Application启动,创建一个配置类如下,配置中包含一个Bean

      1. import org.springframework.context.annotation.Bean;
      2. import org.springframework.context.annotation.Configuration;
      3. @Configuration
      4. public class ConfigC {
      5. @Bean
      6. public AwareTestService awareTestService() {
      7. return new AwareTestService();
      8. }
      9. }

      用于测试设置AwareTestService  实现接口 BeanNameAware, BeanClassLoaderAware,当然也可以实现其他的接口来测试

      1. import org.springframework.beans.factory.BeanClassLoaderAware;
      2. import org.springframework.beans.factory.BeanNameAware;
      3. import org.springframework.stereotype.Service;
      4. @Service
      5. public class AwareTestService implements BeanNameAware, BeanClassLoaderAware {
      6. private ClassLoader classLoader;
      7. private String beanName;
      8. @Override
      9. public void setBeanClassLoader(ClassLoader classLoader) {
      10. this.classLoader=classLoader;
      11. }
      12. @Override
      13. public void setBeanName(String name) {
      14. this.beanName=name;
      15. }
      16. public void getInfo(){
      17. System.out.println(beanName);
      18. System.out.println(classLoader.toString());
      19. }
      20. }

      创建启动类用于测试,通过加载ConfigC来启动容器,并通过getBean方法打印Bean信息

      1. import org.springframework.context.ApplicationContext;
      2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      3. public class AwareTest {
      4. public static void main(String[] args) {
      5. ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigC.class);
      6. AwareTestService b = ctx.getBean(AwareTestService.class);
      7. b.getInfo();
      8. }
      9. }

      运行结果如下

      1. 15:08:17.668 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@768b970c
      2. 15:08:17.681 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
      3. 15:08:17.777 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
      4. 15:08:17.779 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
      5. 15:08:17.780 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
      6. 15:08:17.781 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
      7. 15:08:17.788 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'configC'
      8. 15:08:17.792 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'awareTestService'
      9. awareTestService
      10. jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc


      上一篇:Spring事务问题,同一次请求中相同SQL查询结果不一致

    55. 相关阅读:
      当你使用ChatGPT时,选择合适的提示(prompt)是引导对话方向的关键
      生产管理中,如何做好生产进度控制?
      visual studio code导入自定义模块(pycharm中能够运行的文件,vs code报错:未找到指定模块)
      18-移动端等比例缩放rem
      【设计模式】代理模式
      国际经济学名词解释
      Echarts 有数据,但图不显示(完美解决方案)
      快来带您了解中秋节的前世今生
      Django CreateView视图
      【Liunx】程序的执行过程及gcc/g++的理解
    56. 原文地址:https://blog.csdn.net/Beijing_L/article/details/127095360