spring中Aware结尾常用接口说明

文章转自http://blog.csdn.net/javaloveiphone/article/details/52143126

一、关于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>
  • 1
//实现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实现的项目,可自行下载验证。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值