Spring中的Aware接口详细解析

 更新时间:2023年12月20日 08:32:49   作者:城堡斗士  
这篇文章主要介绍了Spring中的Aware接口详细解析,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接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Javascript判断Crontab表达式是否合法

    详解Javascript判断Crontab表达式是否合法

    这篇文章主要介绍了详解Javascript判断Crontab表达式是否合法的相关资料,需要的朋友可以参考下
    2017-03-03
  • spring boot之SpringApplication 事件监听

    spring boot之SpringApplication 事件监听

    这篇文章主要介绍了spring boot之SpringApplication 事件监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • Spring boot 打jar包分离lib的正确配置方式

    Spring boot 打jar包分离lib的正确配置方式

    spring boot打jar包分离lib后,配置文件的方式,在网上可以搜到很多答案,但是都不够完善,今天小编给大家带来了Spring boot 打jar包分离lib的正确配置方式,感兴趣的朋友一起看看吧
    2018-02-02
  • SpringBoot+Redis+Lua分布式限流的实现

    SpringBoot+Redis+Lua分布式限流的实现

    本文主要介绍了SpringBoot+Redis+Lua分布式限流的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • ssm项目改造spring boot项目完整步骤

    ssm项目改造spring boot项目完整步骤

    Spring Boot现在已经成为Java开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成,下面这篇文章主要给大家介绍了关于ssm项目改造spring boot项目的相关资料,需要的朋友可以参考下
    2023-04-04
  • Spring4整合Hibernate5详细步骤

    Spring4整合Hibernate5详细步骤

    本篇文章主要介绍了Spring4整合Hibernate5详细步骤,具有一定的参考价值,有兴趣的同学可以了解一下
    2017-04-04
  • SpringData Repository接口用法解析

    SpringData Repository接口用法解析

    这篇文章主要介绍了SpringData Repository接口用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Java超详细教你写一个学籍管理系统案例

    Java超详细教你写一个学籍管理系统案例

    这篇文章主要介绍了怎么用Java来写一个学籍管理系统,学籍管理主要涉及到学生信息的增删查改,本篇将详细的实现,感兴趣的朋友跟随文章往下看看吧
    2022-03-03
  • Java中的Null到底是什么

    Java中的Null到底是什么

    null是没有地址,""是有地址但是里面的内容是空的,好比做饭 null说明连锅都没有 而""则是有锅没米,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来详细学习一下它吧
    2019-06-06
  • SpringMVC基于配置的异常处理器

    SpringMVC基于配置的异常处理器

    这篇文章主要为大家介绍了SpringMVC基于配置的异常处理器,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05

最新评论