Spring - aware注入原理
Spring中Aware接口原理
在Spring中存在一个Aware接口,实现该接口可以让我们的Bean获取到Spring容器中特定的资源,但该接口只是个标记接口,不存在任何方法,因此我们还需要继承Aware来做特定资源获取的实现。
换句话说:只要实现了Aware子接口的Bean都能获取到一个Spring底层组件。
从我们熟悉的 refresh() 方法入手, 接下来调用的 prepareBeanFactory() 方法,会添加一些默认的后置处理器,这里我们关注的是添加ApplicationContextAwareProcessor实例。
一、注册时机
ApplicationContextAwareProcessor的注册时机,即准备BeanFactory的时候,注册的入口在AbstractApplicationContext#prepareBeanFactory方法中。
1. refresh
AbstractApplicationContext#refresh
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized(this.startupShutdownMonitor) { 3 StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); 4 this.prepareRefres); 5 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); 6 this.prepareBeanFactory(beanFactory); 7 8 //... 9 10 } 11 }
2. prepareBeanFactory()
AbstractApplicationContext#prepareBeanFactory
1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { 2 beanFactory.setBeanClassLoader(this.getClassLoader()); 3 if (!shouldIgnoreSpel) { 4 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); 5 } 6 7 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); 8 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); 9 10 //... 11 12 }
二、执行逻辑
1. postProcessBeforeInitialization
1)判断是否是xxxAware接口,判断是,则继续往下
2)通过invokeAwareInterfaces里面进行注入
ApplicationContextAwareProcessor#postProcessBeforeInitialization 源码如下:
1 @Nullable 2 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 3 // 判断是否是xxxAware接口,判断是,则继续往下 4 if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) { 5 return bean; 6 } else { 7 AccessControlContext acc = null; 8 if (System.getSecurityManager() != null) { 9 acc = this.applicationContext.getBeanFactory().getAccessControlContext(); 10 } 11 12 if (acc != null) { 13 AccessController.doPrivileged(() -> { 14 this.invokeAwareInterfaces(bean); 15 return null; 16 }, acc); 17 } else { 18 // 在这个方法进行相应的注入 19 this.invokeAwareInterfaces(bean); 20 } 21 22 return bean; 23 } 24 }
2. invokeAwareInterfaces
1)判断是否是xxxAware接口
2) 如果是xxxAware接口,则获取xxx,调用setxxx方法进行注入
ApplicationContextAwareProcessor#invokeAwareInterfaces 源码如下:
1 private void invokeAwareInterfaces(Object bean) { 2 if (bean instanceof Aware) { 3 if (bean instanceof EnvironmentAware) { 4 ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment()); 5 } 6 7 if (bean instanceof EmbeddedValueResolverAware) { 8 ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver); 9 } 10 11 if (bean instanceof ResourceLoaderAware) { 12 ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext); 13 } 14 15 if (bean instanceof ApplicationEventPublisherAware) { 16 ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext); 17 } 18 19 if (bean instanceof MessageSourceAware) { 20 ((MessageSourceAware)bean).setMessageSource(this.applicationContext); 21 } 22 23 if (bean instanceof ApplicationContextAware) { 24 ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); 25 } 26 } 27 28 }
三、执行时机
ApplicationContextAwareProcessor本身并不是扩展点,而是实现了BeanPostProcessor,并实现postProcessBeforeInitialization(),所以并不需要去实现它,但是其内部包含了以下7个接口实现的执行时机,这几个接口的功能作用分别是:
1. EnvironmentAware
用于获取Enviroment,Enviroment可以获得系统内的所有参数;另外也可以通过注入的方式来获得Environment,用哪种方式需要以实现场景而决定。
2. EmbeddedValueResolverAware
用于获取StringValueResolver,StringValueResolver可以获取基于String类型的properties的变量;另外还可以使用@Value的方式来获取properties的变量,用哪种方式需要以实现场景而决定。
3. ResourceLoaderAware
用于获取ResourceLoader,ResourceLoader可以用于获取classpath内所有的资源对象。
4. ApplicationEventPublisherAware
用于获取ApplicationEventPublisher,ApplicationEventPublisher可以用来发布事件,当然这个对象也可以通过spring注入的方式来获得,具体的实现方式可以参考Springboot事件监听机制的实战应用。
5. MessageSourceAware
用于获取MessageSource,MessageSource主要用来做国际化。
6. ApplicationStartupAware
Spring Boot 应用启动过程中进行额外的配置、监控或自定义操作。
7. ApplicationContextAware
用来获取ApplicationContext,ApplicationContext就是Spring上下文管理器。
四、Aware调用链路
1. 调用AbstractAutowireCapableBeanFactory的doCreateBean()方法
2. 调用AbstractAutowireCapableBeanFactory的initializeBean()方法,代码如下:
1 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { 2 if (System.getSecurityManager() != null) { 3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 4 invokeAwareMethods(beanName, bean); 5 return null; 6 }, getAccessControlContext()); 7 } 8 else { 9 invokeAwareMethods(beanName, bean); 10 } 11 12 Object wrappedBean = bean; 13 if (mbd == null || !mbd.isSynthetic()) { 14 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 15 } 16 17 try { 18 invokeInitMethods(beanName, wrappedBean, mbd); 19 } 20 catch (Throwable ex) { 21 throw new BeanCreationException( 22 (mbd != null ? mbd.getResourceDescription() : null), 23 beanName, "Invocation of init method failed", ex); 24 } 25 if (mbd == null || !mbd.isSynthetic()) { 26 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 27 } 28 29 return wrappedBean; 30 }
3. 调用AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInitialization()方法
4. 调用ApplicationContextAwareProcessor的postProcessBeforeInitialization()方法
5. 调用ApplicationContextAwareProcessor的invokeAwareInterfaces()方法
6. 调用Aware接口实现的方法
五、自定义aware
自定义组件时,想要使用spring容器底层的一些组件,比如ApplicationContext、Beanfactory,xxx等,只需要让自定义组件实现xxxAware,在对象实例化的时候,会把spring底层的一些组件注入到自定义的bean中。
举个例子:
1 import org.springframework.beans.factory.BeanFactoryUtils; 2 import org.springframework.context.ApplicationContext; 3 import org.springframework.context.ApplicationContextAware; 4 5 import java.util.Map; 6 7 /** 8 * 通过Spring上下文获取bean工具类 9 * 10 * @author test 11 */ 12 public class SpringContextUtils implements ApplicationContextAware { 13 14 /** 15 * Spring应用上下文环境 16 */ 17 private static ApplicationContext applicationContext; 18 19 @Override 20 public void setApplicationContext(ApplicationContext applicationContext) { 21 SpringContextUtils.initSpringContext(applicationContext); 22 } 23 24 public static ApplicationContext getApplicationContext() { 25 return applicationContext; 26 } 27 28 @SuppressWarnings("unchecked") 29 public static <T> T getBean(String name) { 30 return (T) applicationContext.getBean(name); 31 } 32 33 public static <T> T getBean(Class<T> clazz) { 34 return applicationContext.getBean(clazz); 35 } 36 37 public static boolean isSingleton(String name) { 38 return applicationContext.isSingleton(name); 39 } 40 41 /** 42 * 根据class对象返回IOC容器中其对象和其子类的对象。 43 * 未找到则返回空MAP。 44 * KEY为BEAN ID或者NAME,VALUE为BEAN实例 45 * 46 * @param type 需要找的bean类型的CLASS对象 47 * @return bean映射 48 */ 49 public static <T> Map<String, T> getBeansByType(Class<T> type) { 50 return BeanFactoryUtils.beansOfTypeIncludingAncestors(SpringContextUtils.getApplicationContext(), type); 51 } 52 53 /** 54 * 初始化ApplicationContext 55 * 56 * @param applicationContext 上下文 57 */ 58 public static void initSpringContext(ApplicationContext applicationContext) { 59 SpringContextUtils.applicationContext = applicationContext; 60 } 61 62 /** 63 * 获取业务线(业务线配置在配置文件中) 64 * 65 * @return 业务线 66 */ 67 public static String getProjectBusinessLine() { 68 if (applicationContext == null) { 69 throw new RuntimeException("spring初始化失败"); 70 } 71 return applicationContext.getEnvironment().getProperty("***.application.businessLine"); 72 } 73 74 /** 75 * 获取项目名称(项目名称配置在配置文件中) 76 * 77 * @return 项目名称 78 */ 79 public static String getProjectName() { 80 if (applicationContext == null) { 81 throw new RuntimeException("spring初始化失败"); 82 } 83 return applicationContext.getEnvironment().getProperty("***.application.name"); 84 } 85 }