1. 程式人生 > 實用技巧 >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

到這裡就真相大白,大家可以試試打個斷點程式能不能進到該方法去。