Spring中的Aware接口详细解析
作者:城堡斗士
Aware接口介绍
Aware是一个具有标识作用的超级接口,具体实现是有子接口去决定的,但是子接口至少要有一个带一个参数的且返回是空的方法。实现该接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通过回调。也就是说:直接或间接实现了这个接口的类,都具有被spring容器通知的能力。
Aware翻译过来是adj. 知道的,明白的,察觉到的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware前面的含义。 比如实现了ApplicationContextAware接口的类,能够获取到ApplicationContext,实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。
package org.springframework.beans.factory; /** * A marker superinterface indicating that a bean is eligible to be notified by the * Spring container of a particular framework object through a callback-style method. * The actual method signature is determined by individual subinterfaces but should * typically consist of just one void-returning method that accepts a single argument. * * <p>Note that merely implementing {@link Aware} provides no default functionality. * Rather, processing must be done explicitly, for example in a * {@link org.springframework.beans.factory.config.BeanPostProcessor}. * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor} * for an example of processing specific {@code *Aware} interface callbacks. * * @author Chris Beams * @author Juergen Hoeller * @since 3.1 */ public interface Aware { }
Aware常用子接口如下:
org.springframework.context.ApplicationContextAware
org.springframework.beans.factory.BeanFactoryAware
org.springframework.beans.factory.BeanClassLoaderAware
org.springframework.beans.factory.BeanNameAware
org.springframework.context.EnvironmentAware
org.springframework.context.ResourceLoaderAware
org.springframework.context.annotation.ImportAware
1.ApplicationContextAware
实现该接口的类可以获取spring容器上下文信息 ApplicationContext , ApplicationContextAware接口源码如下:
public interface ApplicationContextAware extends Aware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
下面demo可通过类的静态方法调用来获取applicationContext上下文信息:
@Component public class ApplicationContextStaticProvider implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static ApplicationContext getApplicationContext() { return context; } /** * 通过beanName获取Bean * * @param beanName * @return */ public static Object getBean(String beanName) { return getApplicationContext().getBean(beanName); } /** * 通过class获取bean * * @param clazz * @param <T> * @return */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通过name,以及Clazz返回指定的bean * * @param beanName * @param clazz * @param <T> * @return */ public static <T> T getBean(String beanName, Class<T> clazz) { return getApplicationContext().getBean(beanName, clazz); } } @Service public class DemoBean { public void test(String str){ System.out.println(str); } } public class AnnotationConfigApplicationContextTests { @Test public void scanAndRefreshTestAware() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("org.springframework.context.annotation7"); context.refresh(); DemoBean demoBean= (DemoBean) ApplicationContextStaticProvider.getBean("demoBean"); demoBean.test("test applicationContextAware"); } }
调用过程分析
Spring在初始化Bean时,如何回调ApplicationContextAware接口setApplicationContext方法呢?
我们来看如下调用顺序:
1.AbstractApplicationContext#refresh() ;
2.AbstractApplicationContext#prepareBeanFactory() —> beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
3.AbstractApplicationContext#finishBeanFactoryInitialization();
4.DefaultListableBeanFactory#preInstantiateSingletons()—>getBean(beanName);
5.AbstractAutowireCapableBeanFactory#doCreateBean();
6.AbstractAutowireCapableBeanFactory#initializeBean();填充bean属性后,初始化bean。
7.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization()
8.执行ApplicationContextAwareProcessor.postProcessBeforeInitialization()
9.ApplicationContextAwareProcessor#invokeAwareInterfaces()
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { 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); } // 最终调用ApplicationContextAware.setApplicationContext()方法 if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
第一步: AbstractApplicationContext#refresh()
第二步:给bean工厂配置ApplicationContextAware回调处理 AbstractApplicationContext#prepareBeanFactory() —> beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
第三步:初始化bean的过程(实例化(一般调用构造方法实例化bean)、属性注入、bean初始化),属性注入后,bean初始化前,调用ApplicationContextAware实现类setApplicationContext()方法
2.BeanFactoryAware
Spring Ioc 中最顶层的父接口就是BeanFactory。实现这个BeanFactoryAware接口的子类可以获取spring容器的BeanFactory 对象,进而可以动态的去操作 要在spring容器中注入的bean。
ApplicationContext接口是BeanFactory的子接口,所以继承ApplicationContextAware的实现类拿到ApplicationContext 对象比实现BeanFactoryAware接口拿到BeanFactory 对象 可以获取更多的信息。
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能提前发现一些Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean(单例)。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。 相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。BeanFacotry延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身时检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用 ApplicationContext。应用上下文则会在上下文启动后预载入所有的单实例Bean。通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
3.BeanNameAware
这个接口的含义就是让实现类知道自己在spring容器中定义的beanName是什么,实际开发一般没啥用。
4.BeanClassLoaderAware
获取spring 容器的类加载器ClassLoader 对象; org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final 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); } } }
正常使用的是: Thread.currentThread().getContextClassLoader();
5.EnvironmentAware
实现这个接口的类能获取Environmet对象,进而可以各种系统变量信息,也可以设置 变量的优先级别等等。 通过Environment 对象可以获取spring boot框架中的application.properties中定义的变量值。
6.ResourceLoaderAware
获取资源加载器ResourceLoader 对象,可以获得外部资源文件。
到此这篇关于Spring中的Aware接口详细解析的文章就介绍到这了,更多相关Spring的Aware接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!