[源码系列:手写spring] IOC第十一节:Aware接口

内容介绍

  Aware简洁

        在Spring框架中,Aware接口是一个非常有用的工具,用于实现Bean与Spring容器及其他资源之间的集成。Aware接口是一个标记接口,其中定义了各种Aware子接口,每个子接口对应一种资源。这些子接口的命名约定为"XXXAware",其中XXX表示资源的名称。

        Aware接口的核心思想是将依赖注入的能力扩展到Bean,使其可以主动获取特定类型的资源或信息,而不需要在Bean定义中显式配置这些资源。这种方式有助于提高代码的可维护性,减少Bean之间的耦合度,使得Bean的配置更加灵活。

  使用案例

        当在生产中使用Spring框架时,经常会遇到需要访问应用程序环境配置信息的情况。这可以通过实现`EnvironmentAware`接口来实现。以下是一个更常见且实用的示例,说明了如何使用`EnvironmentAware`接口以及如何访问应用程序的环境配置信息。

    EnvironmentAware 接口介绍:

        EnvironmentAware是Spring框架中的一个Aware接口,用于允许Bean访问应用程序的环境配置信息。这包括了属性文件、系统属性、环境变量等。通过实现EnvironmentAware接口,Bean可以轻松地获取这些配置信息而无需显式读取它们。

    案例:

        假设我们正在开发一个在线商店应用程序,我们希望配置一些与支付相关的属性,如支付网关的URL、商户ID等。这些属性通常会在应用程序的配置文件中定义。我们可以使用`EnvironmentAware`接口来实现此目标。

        首先,定义一个PaymentService类并实现`org.springframework.context.EnvironmentAware`接口:

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

public class PaymentService implements EnvironmentAware {

    private Environment environment;

    public void processPayment(double amount) {
        String paymentGatewayUrl = environment.getProperty("payment.gateway.url");
        String merchantId = environment.getProperty("payment.merchant.id");

        // 使用获取到的配置信息进行支付处理
        System.out.println("Processing payment of $" + amount + " using gateway URL: " + paymentGatewayUrl);
        System.out.println("Merchant ID: " + merchantId);
        // 具体的支付逻辑
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}

接下来,在Spring配置文件中定义Bean,并设置相应的属性:

<!-- 配置PaymentService Bean -->
<bean id="paymentService" class="com.example.PaymentService" />

<!-- 定义应用程序环境配置 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:payment.properties" />
</bean>

        在上面的示例中,我们定义了一个PaymentService,该Bean实现了EnvironmentAware接口以获得Environment实例。在processPayment方法中,我们使用environment.getProperty方法获取了支付网关URL和商户ID的值。这些值在应用程序的配置文件(例如,payment.properties)中定义。

        现在,我们可以轻松地访问应用程序的环境配置信息,而无需硬编码这些值。这种方式使得配置信息的管理更加灵活,可以根据不同的部署环境轻松切换配置文件,而不需要修改Bean的代码。

  常见Aware接口

Spring框架中有许多Aware接口,用于帮助Bean与Spring容器及其他资源进行集成。以下是几个常见的Aware接口及其简单介绍:

常见Aware接口
接口名用途
BeanNameAware允许Bean获取自己在Spring容器中的Bean名称。这可以用于在Bean内部使用其名称进行一些自定义的逻辑处理。
ApplicationContextAware允许Bean获取对Spring应用程序上下文(容器)的引用。这使得Bean能够访问容器中的其他Bean和资源。
EnvironmentAware允许Bean获取对应用程序环境配置的访问权限。通过此接口,Bean可以轻松访问属性文件、系统属性、环境变量等配置信息。
ServletContextAware允许Bean获取对Servlet上下文的引用。这对于与Web应用程序相关的Bean非常有用,例如访问Servlet上下文中的资源和属性。
ResourceLoaderAware允许Bean获取对Spring资源加载器(ResourceLoader)的引用。通过ResourceLoader,Bean可以加载类路径、文件系统等各种资源。
MessageSourceAware允许Bean获取对Spring的国际化(i18n)消息源的引用。这对于在Bean中处理本地化的消息非常有用。
BeanFactoryAware允许Bean获取对Bean工厂的引用。虽然ApplicationContext通常用于创建Bean,但在某些情况下,BeanFactory可能更合适,因此此接口可以用来获取BeanFactory的引用。
EmbeddedValueResolverAware允许Bean获取对属性值解析器(PropertyPlaceholderHelper)的引用,用于解析属性占位符(如${property})。
ApplicationEventPublisherAware允许Bean获取对应用程序事件发布器的引用。Bean可以使用此接口来发布自定义的应用程序事件。
ServletConfigAware允许Bean获取对Servlet配置的引用。这在Web应用程序中非常有用,例如获取Servlet初始化参数。


        这些Aware接口提供了不同类型的访问权限,帮助Bean与Spring容器及其他资源进行集成,提高了应用程序的灵活性和可维护性。根据具体的需求,可以选择实现适当的Aware接口以满足应用程序要求。

目前为止,bean的生命周期如下:
 

当前bean的生命周期

在本节文章中,我们主要实现两个Aware接口

  • BeanFactoryAware接口:

        实现对BeanFactory的感知,具体实现查看AbstractAutowireCapableBeanFactory#initializeBean前三行。

  • ApplicationContextAware接口:

         实现对ApplicationContex的感知,是通过BeanPostProcessor。由当前bean的生命周期可以看出,bean实例化后会经过BeanPostProcessor的前置处理和后置处理。

        定义一个BeanPostProcessor的实现类ApplicationContextAwareProcessor,在AbstractApplicationContext#refresh方法中加入到BeanFactory中,在前置处理中为bean设置所属的ApplicationContext,然后通过调用Bean的setApplicationContext方法,将ApplicationContext设置给这个Bean。这样,Bean就可以在运行时感知到其所在的ApplicationContext了。

代码分支

https://github.com/yihuiaa/little-spring/tree/aware-interfaceicon-default.png?t=N7T8https://github.com/yihuiaa/little-spring/tree/aware-interface

核心代码

AbstractAutowireCapableBeanFactory

....
   protected Object initializeBean(String beanName, Object bean,BeanDefinition beanDefinition){
        if(bean instanceof BeanFactoryAware){
            ((BeanFactoryAware)bean).setBeanFactory(this);
        }
        //执行BeanPostProcessor的前置处理
....

AbstractApplicationContext

....
@Override
	public void refresh() throws BeansException {
		//创建BeanFactory,并加载BeanDefinition
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();

		//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
....

测试

xml

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

    <bean id="helloService" class="service.HelloService"/>

</beans>

 HelloService

public class HelloService implements ApplicationContextAware, BeanFactoryAware {
    private ApplicationContext applicationContext;

    private BeanFactory beanFactory;
   public String hello() {
        System.out.println("hello word!");
        return "hello word!";
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

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

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

AwareInterfaceTest

public class AwareInterfaceTest {

	@Test
	public void test() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
		HelloService helloService = applicationContext.getBean("helloService", HelloService.class);
		System.out.println("ApplicationContext: "+helloService.getApplicationContext());
		System.out.println("BeanFactory: "+helloService.getBeanFactory());
	}
}

测试结果

ApplicationContext: org.springframework.context.support.ClassPathXmlApplicationContext@11531931
BeanFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@5e025e70

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值