Spring源码-Aware接口

2,474 阅读4分钟

日积月累,水滴石穿 😄

Aware

Aware 接口定义如下:

/**
 * 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 接口是一个具有标识作用的超级接口,指示 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回调的方式。Aware 接口是一个空接口,具体的实现由各个子接口决定,且该接口通常只包含一个单个参数并且返回值为void的方法。可以理解就是 set 方法。该方法的命名方式为 set + 去掉接口名中的 Aware 后缀,即 XxxAware 接口,则方法定义为 setXxx(),例如 BeanNameAware(setBeanName)ApplicationContextAware(setApplicationContext)注意,仅实现Aware接口,不会提供任何默认功能,需要明确的指定实现哪个子接口

Spring 中提供了一些以Aware结尾的接口:

image-Aware.png

  • BeanClassLoaderAware:加载Spring Bean的类加载器

  • BeanFactoryAware:让 Bean 获取配置它们的 BeanFactory 的引用

  • BeanNameAware:让 Bean 获取自己在 BeanFactory 配置中的 Name

  • ApplicationContextAware:让 Bean 获取 ApplicationContext 上下文对象

  • EmbeddedValueResolverAware:让 Bean 获取配置文件内容(解析配置文件,与@Value 功能类似)

  • MessageSourceAware:对 MessageSource 的一个包装,处理国际化

  • ResourceLoaderAware:底层访问资源的加载器

  • ApplicationEventPublisherAware:应用事件

实践

Aware 的子接口挺多的,这里实践几个比较眼熟的。为什么说眼熟呢!因为在看源码的时候看到它们了。实践 BeanNameAwareBeanFactoryAwareBeanClassLoaderAwareApplicationContextAware。下面就这前三个接口来做一个简单的演示,先看各自的定义:

public interface BeanClassLoaderAware extends Aware {

 /**
  *  为bean实例提供 BeanClassLoader 的回调函数
  */
 void setBeanClassLoader(ClassLoader classLoader);
}

public interface BeanFactoryAware extends Aware {
 /**
  * 为bean实例提供 BeanFactory 的回调函数
  */
 void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

public interface BeanNameAware extends Aware {
 /**
  * 创建此bean的bean工厂中设置bean的名称
  */
 void setBeanName(String name);
}

下面简单演示下上面三个接口的使用方法:

public class TestAware implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {

    private  String beanName;

    private  BeanFactory beanFactory;

    private  ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
            System.out.println("调用了 setBeanClassLoader()");
            this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("调用了 setBeanFactory()");
            this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
            System.out.println("调用了 setBeanName()");
            this.beanName = name;
    }

    public void test(){
            System.out.println("beanName = " + beanName);
            System.out.println("bean对象 = " + beanFactory.getBean(beanName));
    }
}

xml配置:

<bean class="com.gongj.aware.TestAware" id="testAware"></bean>

启动类:

public static void main(String[] args) {
    ClassPathResource resource = new ClassPathResource("spring-config.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(resource);
    TestAware testAware = (TestAware)factory.getBean("testAware");
    testAware.test();
}
	
结果:
调用了 setBeanName()
调用了 setBeanClassLoader()
调用了 setBeanFactory()
beanName = testAware
bean对象 = com.gongj.aware.TestAware@6e5e91e4

看到结果,我们可以得出实现这些 Aware 接口的Bean在被初始化之后,可以获取相对应的资源。例如实现BeanFactoryAwareBean实例化后Spring容器将会注入BeanFactory的实例。具体源码解析前往:Spring源码(九)-初始化Bean-initializeBean

ApplicationContextAware

为什么要将这个接口单独拎出来将呢?其实是这个接口其实用的比较多。那它的实用场景是什么呢?当没有注册到 Spirng 容器的类(工具类)想要使用 Spirng 容器中的 Bean 的时候,就需要使用 ApplicationContextAware来开发一个SpringUtil类。

  • SpirngUtil
public class SpringUtil implements ApplicationContextAware {

   private static ApplicationContext applicationContext;

   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
   }

   public static  <T> T getBean(String name, Class<T> requiredType) throws BeansException {
      return applicationContext.getBean(name, requiredType);
   }

   public static <T> T getBean(String name) throws BeansException {
      return (T) applicationContext.getBean(name);
   }

   public static <T> T getBean(Class<T> clz) throws BeansException {
      return applicationContext.getBean(clz);
   }

}

创建 SpringUtil类,并实现 ApplicationContextAware接口,在类中提供几个获取 Bean 的方法。

  • DemoUtil
public class DemoUtil {
    public static void test(){
        TestAware testAware = SpringUtil.getBean("testAware", TestAware.class);
        testAware.test();
    }
}

提供静态方法 test,使用 SpringUtil获取Spring容器中的 Bean 。

  • xml 配置增加 SpirngUtil的 Bean 配置
<bean class="com.gongj.aware.SpringUtil" id="spirngUtil"></bean>
  • Main
public static void main(String[] args) {
    ClassPathResource resource = new ClassPathResource("spring-config.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(resource);
    DemoUtil.test();
}

image-20210422213023432.png 从该运行结果可以看出,竟然发生了异常,这是因为使用的容器是 BeanFactory, BeanFactory里的getBean() 方法在激活Aware 接口时只检测了 BeanNameAwareBeanClassLoaderAwareBeanFactoryAware 三个 Aware 接口。需要使用ClassPathXmlApplicationContext容器。

public static void main(String[] args) {
    ClassPathXmlApplicationContext context =
                    new ClassPathXmlApplicationContext("spring-config.xml");
    DemoUtil.test();
}
结果:
调用了 setBeanName()
调用了 setBeanClassLoader()
调用了 setBeanFactory()
beanName = testAware
bean对象 = com.gongj.aware.TestAware@2cdf8d8a

ApplicationContextAware那这个Aware是在什么时候被激活的呢?逻辑位于

ApplicationContextAwareProcessorinvokeAwareInterfaces方法里,内容如下:

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

当前 bean 实现了什么接口,就给这个 bean 设置相对应的对象实例。至于ApplicationContextAwareProcessor 类是一个BeanPostProcessor

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。