Spring中的Aware接口

Spring中的Aware接口

Aware接口

当我们需要用到spring中的底层的一些组件的时候,我们需要自定义bean去实现对应的Aware接口来获取底层组件,如ApplicationContextAware,BeanFactoryAware,BeanNameAware,EnvironmentAware等等

实现ApplicationContextAware接口获取ApplicationContext

package main.beans;

/**
 * @author lgx
 * @date 2020/12/13 13:55
 * @desc
 */
public class BeanB {

    private String id;

    private String name;

    private Integer age;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "BeanA{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

package main.beans;

/**
 * @author lgx
 * @date 2020/12/13 12:21
 * @desc
 */
public class BeanA{

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "BeanA{" +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

复制代码

定义BeanC去实现ApplicationContextAware接口

package main.beans;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author lgx
 * @date 2020/12/13 14:16
 * @desc
 */
public class BeanC implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("main.beans.BeanC.setApplicationContext 执行");
        BeanA bean = applicationContext.getBean(BeanA.class);
        System.out.println("获取BeanA中name属性:" + bean.getName());
    }
}
复制代码

配置spring-config.xml,注册三个bean

    <bean id="beanC" class="main.beans.BeanC"></bean>
    <bean id="beanA" class="main.beans.BeanA">
        <property name="name" value="我是BeanA"></property>
        <property name="age" value="15"></property>
    </bean>

    <bean id="beanB" class="main.beans.BeanB">
        <property name="id" value="15"></property>
        <property name="name" value="我是BeanB"></property>
        <property name="age" value="15"></property>
    </bean>
复制代码

测试结果

package main.beans;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author lgx
 * @date 2020/12/13 12:21
 * @desc
 */
public class Main {


    public static void main(String[] args) {

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
    }
}
复制代码

控制台的输出结果:

main.beans.BeanC.setApplicationContext 执行 获取BeanA中初始化方法中的属性:我是BeanA

疑问:为什么我们实现了ApplicationContextAware接口就能获取到applicationContext呢

ApplicationContextAwareProcessor

这就不得不提到ApplicationContextAwareProcessor这个类了。

ApplicationContextAwareProcessor实现了BeanPostProcessor接口,我们知道该接口可以在Bean的初始化前后去做一些操作。那么我们看看ApplicationContextAwareProcessor实现的方法中的操作

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
         bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
         bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
      return bean;
   }

   AccessControlContext acc = null;

   if (System.getSecurityManager() != null) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
   }

   if (acc != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareInterfaces(bean);
         return null;
      }, acc);
   }
   else {
      invokeAwareInterfaces(bean);
   }

   return bean;
}
复制代码

可以看到如果该bean属性EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware

,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware其中的一种就会走到

invokeAwareInterfaces(bean)方法中来,那么我们来看看该方法是怎么实现的:

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);
   }
    // 在这里将调用自定义bean的setApplicationContext方法并传入applicationContext
   if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}
复制代码

在方法的最后判断到bean属于ApplicationContextAware类型,将将调用自定义bean的setApplicationContext方法并传入applicationContext

到这里就真相大白,大家可以试试打个断点程序能不能进到该方法去。


作者:DQMMD
原文:Spring中的Aware接口 - 掘金

基本上都是可以注入的,所以很少用到了