spring源码学习之Aware分析

还记的我们在#CreateBean(...)方法中其中有一个过程是初始化bean的过程,在初始化的方法中我们其中有一个过程是激活Aware的方法的过程,这节我们来看看Aware到底是什么

Aware接口

该接口位于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 callback
 */
  public interface Aware {

}

该接口主要的作用是一个标记超级接口,实现了该接口的bean是具有回调spring容器的能力,我们可以看到,是一个空接口,实际方法的签名是由各个子接口来实现,通常只接受返回单个参数的seter方法,我们来看一下我们的激活Aware方法的代码:

AbstractAutowireCapableBeanFactory.java
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);
        }
    }
}

代码简单:

  • 如果是BeanNameAware类型的话,调用setXX方法设置属性
  • 如果是BeanClassLoaderAware类型的话,调用setBeanClassLoader设置属性
  • 如果是beanFactoryAware类型的话,调用setBeanFactory设置属性
Aware的实现类

我们来看一下实现了Aware接口的子类

image

这只是其中的一部分实现,图来自大佬芋艿的博客,大家可以去看看,接下来我们自己可以实现自己的Aware方法:

''''''
public interface BeanClassLoaderAware extends Aware {

/**
* 将 BeanClassLoader 提供给 bean 实例回调
* 在 bean 属性填充之后、初始化回调之前回调,
* 例如InitializingBean的InitializingBean.afterPropertiesSet()方法或自定义init方法
*/
void setBeanClassLoader(ClassLoader classLoader);


public interface BeanFactoryAware extends Aware {

   /**
* 将 BeanFactory 提供给 bean 实例回调
* 调用时机和 setBeanClassLoader 一样
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;

public interface BeanNameAware extends Aware {

/**
* 在创建此 bean 的 bean工厂中设置 beanName
*/
void setBeanName(String name);

}


public interface ApplicationContextAware extends Aware {

/**
 * 设置此 bean 对象的 ApplicationContext,通常,该方法用于初始化对象
 */
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

常见的四种实现Aware接口的子类,我们来看case

  public class MyAwareCase implements
    BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, ApplicationContextAware {

private String beanName;
private ClassLoader classLoader;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
public void setBeanClassLoader(ClassLoader classLoader) {

    this.classLoader = classLoader;
    System.out.println("调用:BeanClassLoaderAware的setBeanClassLoader方法");

}

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

    this.beanFactory = beanFactory;
    System.out.println("调用:BeanFactoryAware的setBeanFactory方法");

}

public void setBeanName(String name) {
    this.beanName = name;
    System.out.println("调用:BeanNameAware的setBeanName方法");

}

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    this.applicationContext = applicationContext;
    System.out.println("调用:ApplicationContextAware的setApplicationContext方法");

}

public void display(){
    System.out.println("beanName:" + beanName);
    System.out.println("是否为单例:" + beanFactory.isSingleton(beanName));
    System.out.println("系统环境为:" + applicationContext.getEnvironment());
}

测试方法如下:

public class AwareTest {

public static void main(String[] args) {

    ClassPathResource resource = new ClassPathResource("awareConfig.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
     reader.loadBeanDefinitions(resource);
    MyAwareCase myAwareCase = (MyAwareCase)factory.getBean("myAwareCase");
    myAwareCase.display();
}

配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="myAwareCase" class="com.sgcc.aware.MyAwareCase">
    <property name="beanName" value="beanName"/>
    <property name="beanFactory" value="beanFactory"/>
    <property name="beanClassLoader" value="beanClassLoader"/>
    <property name="applicationContext" value="applicationContext"/>
</bean>
</beans>

很意外,我运行时报了一个错误,大概知道问题所在,这里我把错误贴出来,有知道解决的可以留个言,在这里我先谢过了

Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.beans.factory.BeanFactory' for property 'beanFactory'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.beans.factory.BeanFactory' for property 'beanFactory': no matching editors or conversion strategy found
at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:604)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:219)

从异常信息来看是因为属性beanFactory在匹配类型的过程中出现的问题.它需要的是一个BeanFactory类型的属性value,我这里是String,可能是这个原因造成的

总结

经过简单的case,我们发现Aware接口的实质,spring主要来检测当前bean是否实现了Aware接口,如果实现了,则通过setxxx设置对应的属性给bean,之后我们的bean就有了从spring容器中获取资源的权限了......

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本来是准备看一看Spring源码的。然后在知乎上看到来一个帖子,说有一群**自己连Spring官方文档都没有完全读...
    此鱼不得水阅读 11,816评论 4 21
  • 作者: 一字马胡 转载标志 【2017-12-29】 更新日志 日期更新内容备注2017-12-29创建分析文档...
    一字马胡阅读 14,151评论 2 32
  • 参考W3C Spring教程 Spring致力于J2EE应用的各种解决方案,而不仅仅专注于某一层解决方案。可以说S...
    王侦阅读 4,858评论 0 6
  • 2.1 我们的理念是:让别人为你服务 IoC是随着近年来轻量级容器(Lightweight Container)的...
    好好学习Sun阅读 7,632评论 0 11
  • 计划po来了 监督监督我 今日6号 争取下个月4号前结束掉第一遍 晚上约了闺蜜看《我不是药神》 路上可以听听视频
    更二genger16阅读 1,040评论 0 0