chapter08_Aware感知容器对象

一、简介

Bean对象实现各种Aware接口,Spring就可以在合适的时机调用,感知特定的信息

  • 例如让Bean感知到BeanFactory,BeanName,ApplicationContext

二、实现Aware

2.1 定义Aware接口

  • 标记类接口,实现该接口可以被Spring容器感知
public interface Aware {

}

2.2 定义感知类

提供四个子接口,感知不同类型的信息

请添加图片描述

BeanNameAware,感知BeanName

public interface BeanNameAware extends Aware{
    void setBeanName(String name);
}

BeanFactoryAware,感知BeanFactory

public interface BeanFactoryAware extends Aware{
    void setBeanFactory(BeanFactory beanFactory);
}

BeanClassLoaderAware,感知ClassLoader

public interface BeanClassLoaderAware extends Aware{
    void setBeanClassLoader(ClassLoader classLoader);
}

ApplicationContextAware,感知ApplicationContext

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext);
}

2.3 spring感知Aware的位置

修改AbstractAutowireCapableBeanFactory 类的initializeBean 方法

  • 根据Bean实现的Aware接口,传入对应的属性
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
    // invokeAwareMethods
    if (bean instanceof Aware) {
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        if (bean instanceof BeanClassLoaderAware){
            ((BeanClassLoaderAware) bean).setBeanClassLoader(ClassUtil.getClassLoader());
        }
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
    }

    ······
}

2.4 特殊处理ApplicationContextAware

为什么要特殊处理?

  • 因为BeanFactory是ApplicationContext的一个属性,BeanFactory创建Bean的时候,无法拿到ApplicationContext,所以我们需要通过某种方式,将ApplicationContext传递给BeanFactory

如何实现?

  • 目前我们只有两种方式,BeanFactoryPostProcessor和BeanPostProcessor,由于BeanFactoryPostProcessor本质是通过PropertyValues传递,这样就会强制Bean必须有一个叫做ApplicationContext的属性,这样就不太灵活。因此使用BeanPostProcessor来传递,只需在初始化前方法设置Application属性即可。

新建一个ApplicationContextAwareProcessor

  • 在其中提供一个ApplicationContext属性,在实例化的时候就传入值
public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;

    public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(applicationContext);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

在refresh方法重建BeanFactory的时候,传递ApplicationContext

@Override
public void refresh() {
    // 1. 创建 BeanFactory,并加载 BeanDefinition
    refreshBeanFactory();

    // 2. 获取 BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();

    // 3. 需要特殊处理的Aware,通过BeanPostProcessor传递ApplicationContext
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    // 4. 在Bean实例化之前,执行 BeanFactoryPostProcessor
    invokeBeanFactoryPostProcessors(beanFactory);

    // 5. BeanPostProcessor需要提前于其他Bean对象实例化之前执行注册操作
    registerBeanPostProcessors(beanFactory);

    // 6. 提前实例化单例Bean对象,主动触发getBean
    beanFactory.preInstantiateSingletons();
}

同样在initializeBean()方法,会自动调用applyBeanPostProcessorsBeforeInitialization(),注入ApplicationContext

protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
    
    ······

    //执行BeanPostProcessor的前置处理(初始化前)
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

		······
}

三、测试

让Person实现四个Aware接口

@Slf4j
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Person implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware {
    private String name;
    private int age;
    private Cat cat;

    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        log.info("ClassLoader:" + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        log.info("Bean Name is:" + name);
    }

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

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="cat" class="cn.shopifymall.springframework.test.bean.Cat">
        <property name="name" value="tomcat"/>
        <property name="weight" value="2000"/>
    </bean>

    <bean id="person" class="cn.shopifymall.springframework.test.bean.Person">
        <property name="name" value="LeBron James"/>
        <property name="age" value="18"/>
        <property name="cat" ref="cat"/>
    </bean>

</beans>

测试类

public class ApiTest {

    @Test
    public void test_aware() {
        // 1.初始化 BeanFactory
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

        // 2. 获取Bean对象调用方法
        Person person = (Person) applicationContext.getBean("person");
        System.out.println("测试结果:" + person);
    }
}

控制台打印

  • ClassLoader
  • BeanName
16:19:07.323 [main] INFO cn.shopifymall.springframework.test.bean.Person - ClassLoadersun.misc.Launcher$AppClassLoader@18b4aac2
16:19:07.325 [main] INFO cn.shopifymall.springframework.test.bean.Person - Bean Name is:person

Debugger效果

  • ApplicationContext
  • BeanFactory

请添加图片描述

至此,四个Aware,都完成了注入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值