• Spring aware接口理解


    1. aware接口的作用

    通过aware接口可以获取Spring容器相关信息,但这样会与Spring容器耦合。

    2. 常用aware接口及作用

    执行顺序从上到下。

    类名作用
    BeanNameAware获得容器中bean名称
    BeanClassLoaderAware获得类加载器
    BeanFactoryAware获得bean创建工厂
    EnvironmentAware获得环境变量
    EmbeddedValueResolverAware获取spring容器加载的properties文件属性值
    ResourceLoaderAware获得资源加载器
    ApplicationEventPublisherAware获得应用事件发布器
    MessageSourceAware获得文本信息
    ApplicationContextAware获得当前应用上下文

    3. 使用样例:ApplicationContextAware 在Bean中获取上下文

    
    /**
     * 获取spring注入对象方法
     */
    @Component("springUtil")
    public final class SpringUtil implements ApplicationContextAware {
        /**
         * 应用上下文
         */
        private static ApplicationContext applicationContext;
        /**
         * public方法可能被调用,导致线程不安全。这样写也是为了通过sonar检测
         * @param applicationContext 通过aware设置上下文
         */
        @Override
        public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
            synchronized (SpringUtil.class) {
                if (null == SpringUtil.applicationContext) {
                    SpringUtil.applicationContext = applicationContext;
                }
            }
        }
    
        /**
         * 获取注入对象
         *
         * @param name 对象名称
         * @return 指定注入对象
         */
        public static Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }
    
        private static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        /**
         * 获取注入对象
         *
         * @param clazz 对象类型
         * @param    泛型
         * @return 指定注入对象
         */
        public static <T> T getBean(Class<T> clazz) {
            return getApplicationContext().getBean(clazz);
        }
    
        /**
         * 获取注入对象
         *
         * @param name  对象名称
         * @param clazz 对象类型
         * @param    泛型
         * @return 指定注入对象
         */
        public static <T> T getBean(String name, Class<T> clazz) {
            return getApplicationContext().getBean(name, clazz);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    4. 自定义aware的方式

    先定义一个继承Aware的接口,然后注册一个实现BeanPostProcessor接口的Bean,在postProcessBeforeInitialization中处理Aware接口的逻辑。

    举一个例子。获取调用自定义Aware接口方法的时间。

    4.1 定义继承Aware的接口

    public interface TimeAware extends Aware {
        void setTriggerTime(Date date);
    }
    
    • 1
    • 2
    • 3

    4.2 注册实现BeanPostProcessor接口的Bean

    @Component
    public class AwarePostProcessor implements BeanPostProcessor {
        private final ConfigurableApplicationContext applicationContext;
        /**
         * 可写可不写,这个构造是为了获取applicationContext
         */
        public AwarePostProcessor(ConfigurableApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof Aware) {
                if (bean instanceof TimeAware) {
                    // 实现自定义Aware接口的逻辑,设置调用的时间
                    ((TimeAware)bean).setTriggerTime(new Date());
                }
            }
            return bean;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.3 实现TimeAware接口,并测试

    @Import(AwarePostProcessor.class)
    public class Test implements TimeAware {
        Date date;
        @Override
        public void setTriggerTime(Date date) {
            this.date = date;
        }
    
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(Test.class);
            Test bean = context.getBean(Test.class);
            System.out.println(bean.date);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    结果:
    在这里插入图片描述

    5. 源码处理方式

    Bean实例化->填充属性->初始化,在初始化阶段将实现aware接口的Bean的方法执行。

    1. 先执行实现了下面三个aware接口的方法
    • BeanNameAware
    • BeanClassLoaderAware
    • BeanFactoryAware
    1. 调用初始化方法
    2. 执行实现剩下aware接口的方法

    5.1 初始化阶段的源码逻辑

    AbstractAutowireCapableBeanFactory#initializeBean

    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    		if (System.getSecurityManager() != null) {
    			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    				invokeAwareMethods(beanName, bean);
    				return null;
    			}, getAccessControlContext());
    		}
    		else {
    			/**
    			 * 调用Bean实现的Aware接口的方法,主要包括下面三个接口
    			 * BeanNameAware ----> setBeanName()
    			 * BeanClassLoaderAware ----> setBeanClassLoader()
    			 * BeanFactoryAware  ----> setBeanFactory()
    			 */
    			invokeAwareMethods(beanName, bean);
    		}
    
    		Object wrappedBean = bean;
    		if (mbd == null || !mbd.isSynthetic()) {
    			/** 调用Bean对象的postProcessBeforeInitialization方法,此处会执行标注@PostConstruct注解的方法 */
    			// 此处会调用ApplicationContextAwareProcessor执行其他的aware方法.
    			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    		}
    
    		try {
    			/**
    			 * 执行Bean的初始化方法:
    			 *
    			 * 1.先判断Bean是否实现了InitializingBean接口,如果实现了InitializingBean接口,则调用Bean对象的afterPropertiesSet方法;
    			 * 2.然后判断Bean是否有指定init-method方法,如果指定了init-method方法,则调用bean对象的init-method指定的方法.
    			 */
    			invokeInitMethods(beanName, wrappedBean, mbd);
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(
    					(mbd != null ? mbd.getResourceDescription() : null),
    					beanName, "Invocation of init method failed", ex);
    		}
    		if (mbd == null || !mbd.isSynthetic()) {
    			/**
    			 * 调用Bean对象的postProcessAfterInitialization方法
    			 *
    			 * 如果需要创建代理,在该步骤中执行postProcessAfterInitialization方法的时候会去创建代理
    			 * 调用AbstractAutoProxyCreator类的postProcessAfterInitialization方法,然后调用wrapIfNecessary方法去创建代理.
    			 *
    			 *
    			 * 另外还有一些Aware接口,也会在该步骤中执行,例如:ApplicationContextAwareProcessor后置处理器,对应的setApplicationContext方法会被执行.
    			 */
    			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    		}
    
    		return wrappedBean;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    5.2 实现前三个aware接口的处理

    调用initializeBean =>invokeAwareMethods方法将前三个aware方法调用
    AbstractAutowireCapableBeanFactory#invokeAwareMethods

    private void invokeAwareMethods(String beanName, Object bean) {
    		if (bean instanceof Aware) {
    			if (bean instanceof BeanNameAware) {
    				((BeanNameAware) bean).setBeanName(beanName);
    			}
    			if (bean instanceof BeanClassLoaderAware) {
    				ClassLoader bcl = getBeanClassLoader();
    				if (bcl != null) {
    					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    				}
    			}
    			if (bean instanceof BeanFactoryAware) {
    				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    5.3 剩余实现aware接口的Bean的处理

    调用initializeBean =>applyBeanPostProcessorsBeforeInitialization=>BeanPostProcessor.postProcessBeforeInitialization
    进入ApplicationContextAwareProcessor#postProcessBeforeInitialization=>invokeAwareInterfaces

    private void invokeAwareInterfaces(Object bean) {
    		if (bean instanceof EnvironmentAware) {
    			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    		}
    		if (bean instanceof EmbeddedValueResolverAware) {
    			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    		}
    		if (bean instanceof ResourceLoaderAware) {
    			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    		}
    		if (bean instanceof ApplicationEventPublisherAware) {
    			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    		}
    		if (bean instanceof MessageSourceAware) {
    			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    		}
    		if (bean instanceof ApplicationContextAware) {
    			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    因此可以自定义aware接口,并且注册一个实现BeanPostProcessor的postProcessBeforeInitialization方法的Bean,处理调用aware方法时的处理逻辑。

  • 相关阅读:
    React Hooks学习笔记
    rsync远程同步
    探索现代办公应用系统架构:构建高效、可扩展的工作平台
    ENSP中用OSPF协议在MGRE结构中实现全网可达
    几个简单的JavaScript面试题
    代码随想录笔记_动态规划_416分割等和子集
    大厂真题:【贪心】大疆2023秋招-矩形田地
    SPA项目之主页面--动态树&右侧内容管理
    【Linux初阶】Linux工具学前常识 | 软件生态 | Linux下的软件安装与卸载
    基于张成方案建立秘密分割方案
  • 原文地址:https://blog.csdn.net/dreambyday/article/details/126561101