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");
	}
}

1.1 调用过程分析

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中定义的变量值。

5.ResourceLoaderAware

  获取资源加载器ResourceLoader 对象,可以获得外部资源文件。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值