Spring整理系列(06)——spring中Aware结尾接口

本文详细介绍了Spring框架中Aware接口的功能与应用场景,包括BeanFactoryAware、BeanNameAware等,并通过示例展示了如何利用这些接口获取Spring容器资源。此外,还讨论了在不同项目间跨容器获取Bean的方法。

一、关于spring中Aware结尾接口介绍:

Spring中提供一些Aware结尾相关接口,像是BeanFactoryAware、 BeanNameAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。

实现这些 Aware接口的Bean在被实例化
之后,可以取得一些相对应的资源,例如实现BeanFactoryAware的Bean在实例化后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的Bean,在Bean被实例化后,将会被注入 ApplicationContext的实例等等。

通过重写setter方法,当前bean被实例化后实现相关实例的注入。

二、以BeanNameAware、ApplicationContextAware接口举例说明:

<bean name ="myContext" class="com.jsun.test.springDemo.aware.MyApplicationContext"></bean>
//实现BeanNameAware接口,并重写setBeanName()方法,让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)
//实现ApplicationContextAware接口,并重写setApplicationContext()方法
public class MyApplicationContext implements BeanNameAware,ApplicationContextAware{
    private String beanName;

    //注入的beanName即为MyApplicationContext在BeanFactory配置中的名字(根据情况是id或者name)
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
        System.out.println("MyApplicationContext beanName:"+beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        //通过重写的接口方法,获取spring容器实例context,进而获取容器中相关bean资源
        System.out.println(context.getBean(this.beanName).hashCode());

    }

}
    @Test
    public void testScope(){
        //单元测试再次获取bean,并输出bean的hashCode
        System.out.println(super.getBean("myContext").hashCode());
    }

上面输出结果:

信息: Loading XML bean definitions from URL [file:/E:/workspace/springDemo/target/classes/spring-ioc.xml]
MyApplicationContext beanName:myContext
1663216960
1663216960
八月 07, 2016 4:25:12 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@5531a519: startup date [Sun Aug 07 16:25:11 CST 2016]; root of context hierarchy

注意:除了通过实现Aware结尾接口获取spring内置对象,也可以通过@Autowired注解直接注入相关对象,如下:
(如果需要用到静态方法中,如工具方法,还是采用实现接口的方式)

@Autowired
private MessageSource messageSource; 

@Autowired
private ResourceLoader resourceLoader; 

@Autowired
private ApplicationContext applicationContext;

三、实际项目应用遇到的情况:

注:因为与作用域相关,Spring整理系列(04)——spring bean的作用域已有描述,此处再次引用,同时添加代码验证。

1、项目support作为基本的支持包,提供了获取spring容器中bean的公共方法,该方法所属bean被spring容器管理

1)、support项目spring-context.xml配置文件:

    <!-- 启动自动扫描 -->
    <context:component-scan base-package="com.test.spring.support"></context:component-scan>

2)、创建TestBean类,被spring容器管理,相当于业务bean:

package com.test.spring.support;

import org.springframework.stereotype.Component;

/** 
 * @date 创建时间:2016年8月8日 上午11:07:42 
 * @Description: support包中测试bean,相当于实例项目业务bean
 */
@Component("testBean")
public class TestBean {
    public TestBean(){
        System.out.println("TestBean 实例化。");
    }
}

3)、创建SpringContextHolder类,被spring容器管理,同时,该类持有spring容器实例,提供静态公共方法,获取spring容器中管理的bean,如获取TestBean的实例bean:

package com.test.spring.support;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

/**
 * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
 * 
 */
@Service()
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    private static ApplicationContext applicationContext = null;

    /**
     * 实现ApplicationContextAware接口, 注入Context到静态变量中.
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        if (SpringContextHolder.applicationContext != null) {
            System.out.println("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
        }
        System.out.println("Spring容器启动,将容器实例注入到SpringContextHolder实例bean中");
        SpringContextHolder.applicationContext = applicationContext;
    }

    /**
     * 实现DisposableBean接口,重写destroy方法,相当于destroy-method,bean被销毁的时候被调用,
     * 实现在Context关闭时清理静态变量的目的
     * 令:还有InitializingBean接口,重写afterPropertiesSet方法,相当于init-method,bean被实例化的时候被调用
     */
    @Override
    public void destroy() throws Exception {
        applicationContext = null;
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }
}

4)、创建单元测试类TestSpringContextHolder和单元测试方法,加载启动spring容器,并通过上面第三步SpringContextHolder提供的静态方法获取上面第二步被spring容器管理的TestBean的实例bean:

package com.test.spring.support;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 单元测试类
 */
public class TestSpringContextHolder{

    @Test
    public void testGetBean(){
        //获取bean
        SpringContextHolder.getBean("testBean");
    }

    //以下为容器实例声明及初始化、销毁
    private ClassPathXmlApplicationContext context;

    @Before
    public void before(){
        try {
            // xml文件用逗号或者空格符隔开,均可加载
            context = new ClassPathXmlApplicationContext("spring-context.xml");
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }
    @After
    public void after(){
        context.destroy();
    }
}

5)、执行单元测试,结果如下:

信息: Loading XML bean definitions from class path resource [spring-context.xml]
Spring容器启动,将容器实例注入到SpringContextHolder实例bean中
TestBean 实例化。
。。。ClassPathXmlApplicationContext doClose
信息: Closing 。。ClassPathXmlApplicationContext@90f405e。。

上述结果可以得知,通过SpringContextHolder提供的静态方法可以获取spring容器中管理的bean对象。

2、项目biz运行过程中,需要使用support包提供的公共方法获取当前biz项目的某个bean,作为临时注入bean使用
1)、biz项目spring-context.xml文件:

    <!-- 启动自动扫描,base-package 如果多个,用“,”分隔 -->
    <context:component-scan base-package="com.test.spring.biz"></context:component-scan>

2)、biz项目中的业务bean:

package com.test.spring.biz;

import org.springframework.stereotype.Component;

/** 
 * @date 创建时间:2016年8月8日 上午11:29:53 
 * @Description: 业务bean
 */
@Component("bizTmpBean")
public class BizTmpBean {

    public void sayHello(){
        System.out.println("bizTmpBean say hello");
    }
}

3)、biz项目中的公共静态类,提供静态方法,通过调用support项目静态类SpringContextHolder提供的方法获取biz项目中spring容器管理的bean:

package com.test.spring.biz;

import org.springframework.stereotype.Service;

import com.test.spring.support.SpringContextHolder;

/** 
 * @Description: biz项目中,全局静态类,通过support项目包提供的公共静态方法,获取临时bean,调用临时bean的方法
 */
@Service
public class Global {
    public static void globalGetBean(){
        //获取临时bean,调用临时bean的方法
        try{
            BizTmpBean bizTmpBean = SpringContextHolder.getBean("bizTmpBean");

            bizTmpBean.sayHello();
        }catch(NullPointerException e){
            System.out.println("静态获取临时bean失败");
            e.printStackTrace();
        }
    }
}

4)、创建biz项目的单元测试类TestGlobal,用于验证biz项目的静态类Global是否可以临时获取到某个bean:

package com.test.spring.biz;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** 
 * @date 创建时间:2016年8月8日 上午10:49:13 
 * @Description: biz项目中单元测试类
 */
public class TestGlobal {

    //单元测试方法
    @Test
    public void testGlobal(){
        //单元测试,biz项目全局静态类获取临时bean
        Global.globalGetBean();
    }

    //以下为容器实例声明及初始化、销毁
    private ClassPathXmlApplicationContext context;

    @Before
    public void before(){
        try {
            // xml文件用逗号或者空格符隔开,均可加载
            context = new ClassPathXmlApplicationContext("spring-context.xml");
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }
    @After
    public void after(){
        context.destroy();
    }
}

5)、执行结果如下,抛出空指针异常:

信息: Loading XML bean definitions from class path resource [spring-context.xml]
静态获取临时bean失败
java.lang.NullPointerException
    at com.test.spring.support.SpringContextHolder.getBean(SpringContextHolder.java:51)
    at com.test.spring.biz.Global.globalGetBean(Global.java:15)
    at com.test.spring.biz.TestGlobal.testGlobal(TestGlobal.java:18)
。。。
。。。ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext。。。

3、上面问题产生的原因是:support中一个bean类SpringContextHolder通过实现ApplicationContextAware接口获取spring容器中管理的bean,但它只能从自己所在的spring容器中获取(SpringContextHolder的bean也是被spring容器管理的),现在想通过它从biz的spring容器中获取bean,就出现了夸spring容器的问题,临时性bean将注入失败。

解决的办法,很简单,就是让biz的spring管理support提供公共方法的那个bean类,即让biz项目对SpringContextHolder进行自动扫描。

biz项目spring-context.xml文件更改:

    <!-- 启动自动扫描,添加SpringContextHolder类所在包com.test.spring.support的扫描,base-package 如果多个,用“,”分隔 -->
    <context:component-scan base-package="com.test.spring.support,com.test.spring.biz"></context:component-scan>

执行结果如下:

信息: Loading XML bean definitions from class path resource [spring-context.xml]
Spring容器启动,将容器实例注入到SpringContextHolder实例bean中
TestBean 实例化。
bizTmpBean say hello
八月 08, 2016 2:13:01 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@484adff7: startup date [Mon Aug 08 14:13:01 CST 2016]; root of context hierarchy


注:上面验证代码包位于spring-aware接口实现与bean作用域(spring多容器层面) ,基于maven实现的项目,可自行下载验证。

<think>首先,用户的问题是关于Spring框架中各个Aware接口的功能和使用场景。我需要基于提供的引用信息来构建一个结构清晰的回答。 回顾系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 用户的问题不涉及数学表达式,所以我不需要使用LaTeX数学格式。但如果有数学相关的内容,我会遵守规则。这里似乎没有。 现在,分析用户的问题:"我想了解Spring框架中各种Aware接口的作用 请问Spring框架中各个Aware接口的功能和使用场景" 提供的引用信息: - 引用[1]:Aware接口允许Bean感知Spring容器的内部状态和上下文信息。 - 引用[2]:Aware接口赋予Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以获取Spring容器中的资源引用。 - 引用[3]:使用Aware接口可以使Bean更加灵活,但增加了与Spring框架的耦合;应尽量避免除非必要。 - 引用[4]:列出了各种Aware接口及其作用,如ApplicationContextAware、BeanFactoryAware等。 我需要基于这些信息构建回答。回答应该结构清晰,逐步解释。 结构化回答: 1. **介绍Aware接口**:概述Aware接口是什么,为什么使用它。 2. **主要Aware接口的功能和使用场景**:详细说明每个接口,基于引用[4]。 3. **优缺点和最佳实践**:讨论使用Aware接口的优缺点,基于引用[3]。 4. **总结**:简要总结。 5. **生成相关问题**:在回答末尾添加相关问题。 确保引用标识:在引用的内容末尾添加[^数字]。 引用[4]提供了具体的接口列表: - ApplicationContextAware - BeanFactoryAware - BeanNameAware - 等等 我需要覆盖这些接口的功能和使用场景。 回答结构: - 开头:解释Aware接口的概念。 - 主体:逐一介绍主要Aware接口。 - 结尾:讨论使用注意事项。 - 最后:添加相关问题。 使用中文回答。 生成相关问题:基于主题,生成2-3个相关问题。 最终回答: - 确保真实可靠:基于提供的引用,不要添加虚构信息。</think>### Spring框架中Aware接口的功能和使用场景 在Spring框架中,Aware接口是一种核心机制,它允许Bean感知Spring容器的内部状态和上下文信息。通过实现这些接口,Bean可以在运行时动态地访问容器资源(如ApplicationContext或BeanFactory),从而增强灵活性和控制力。然而,过度使用Aware接口会增加代码与Spring框架的耦合,降低可移植性,因此建议仅在必要时使用[^3]。下面我将逐步介绍主要Aware接口的功能、使用场景和实际应用。 #### 1. **Aware接口概述** - **功能**:Aware接口赋予Bean自感知能力,使其能够直接获取Spring容器中的资源或服务,而无需依赖依赖注入(DI)。这似于`@Autowired`注解,但提供了更底层的访问方式[^2][^4]。 - **核心原理**:当Bean实现某个Aware接口时,Spring容器在初始化Bean时会自动调用对应的setter方法,注入所需的资源。例如,实现`ApplicationContextAware`接口后,容器会注入`ApplicationContext`实例。 - **使用场景**:适用于需要动态访问容器资源的场景,如获取Bean名称、访问Servlet上下文或处理事件发布。但应避免滥用,以减少框架耦合[^1][^3]。 #### 2. **主要Aware接口的功能和使用场景** 基于引用[4]的信息,以下是Spring框架中常见的Aware接口及其详细说明。每个接口都通过一个简单示例来展示典型用法。 - **ApplicationContextAware** - **功能**:允许Bean获取Spring的`ApplicationContext`实例,从而访问容器中的所有Bean、配置和环境属性。 - **使用场景**:在需要动态加载其他Bean或读取配置时使用,例如在自定义工具中管理Bean生命周期。 - **示例代码**: ```java public class MyBean implements ApplicationContextAware { private ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) { this.context = applicationContext; // 注入ApplicationContext } public void doSomething() { Object bean = context.getBean("someBean"); // 动态获取Bean } } ``` - **BeanFactoryAware** - **功能**:提供对`BeanFactory`的访问,`BeanFactory`是Spring容器的基础接口,支持Bean的创建和依赖注入。 - **使用场景**:适用于需要底层容器操作的场景,如延迟加载Bean或自定义Bean实例化过程。 - **示例代码**: ```java public class MyBean implements BeanFactoryAware { private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; // 注入BeanFactory } public void createBean() { MyBean bean = beanFactory.getBean(MyBean.class); // 获取Bean实例 } } ``` - **BeanNameAware** - **功能**:允许Bean获取其在Spring容器中注册的名称(Bean ID)。 - **使用场景**:在日志记录或调试时,需要输出Bean名称以跟踪上下文信息。 - **示例代码**: ```java public class MyBean implements BeanNameAware { private String beanName; @Override public void setBeanName(String name) { this.beanName = name; // 注入Bean名称 } public void logName() { System.out.println("Bean name: " + beanName); // 使用Bean名称 } } ``` - **ServletContextAware** - **功能**:提供对Web应用中的`ServletContext`的访问,用于处理Servlet相关资源(如上下文参数)。 - **使用场景**:在Web应用中,读取或设置Servlet上下文属性,例如初始化全局配置。 - **示例代码**: ```java public class MyWebBean implements ServletContextAware { private ServletContext servletContext; @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; // 注入ServletContext } public void initConfig() { String config = servletContext.getInitParameter("appConfig"); // 获取配置 } } ``` - **MessageSourceAware** - **功能**:允许Bean访问`MessageSource`资源,用于国际化和多语言支持。 - **使用场景**:在需要动态加载消息资源(如i18n消息)时使用,例如用户界面中的本地化文本。 - **示例代码**: ```java public class MyI18nBean implements MessageSourceAware { private MessageSource messageSource; @Override public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; // 注入MessageSource } public String getMessage(String code) { return messageSource.getMessage(code, null, Locale.getDefault()); // 获取本地化消息 } } ``` - **其他常见Aware接口** - **ApplicationEventPublisherAware**:用于发布应用事件(如自定义事件),支持事件驱动架构[^4]。 - **ResourceLoaderAware**:提供对资源加载器的访问,用于读取文件或路径资源。 - **LoadTimeWeaverAware**:在加载时织入第三方模块(如AspectJ),用于AOP增强。 - **ServletConfigAware**:在Servlet环境中访问`ServletConfig`,用于处理特定Servlet配置。 #### 3. **优缺点和最佳实践** - **优点**:Aware接口增强了Bean的灵活性,使Bean能在运行时与容器互动,获取必要的资源和服务[^2][^3]。 - **缺点**:增加了代码与Spring框架的耦合,降低了可移植性。如果过度使用,可能导致代码难以测试和维护[^3]。 - **最佳实践**: - 仅在依赖注入(如`@Autowired`)无法满足需求时使用Aware接口,例如需要直接访问容器底层API。 - 优先考虑使用Spring的注解(如`@Value`或`@Autowired`)来减少耦合。 - 在非必要场景避免使用,以保持代码的独立性和可移植性[^1][^3]。 #### 总结 Aware接口Spring框架中强大的工具,通过实现特定接口(如`ApplicationContextAware`或`BeanNameAware`),Bean可以感知并访问容器资源。这适用于动态资源管理、事件处理等场景,但应谨慎使用以避免不必要的框架依赖。在实际开发中,结合Spring的依赖注入机制,可以构建更健壮的应用[^1][^2][^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值