一个简单的基于 spring-Junit 测试基础搭建——spring必须了解的几个接口系列一

分为以下几部:

1.写上下文的工具类,需继承  ApplicationContextAware 并实现 setApplicationContext方法,定义静态变量 private static ApplicationContext applicationContext; 给静态变量ApplicationContext赋值,再定义一个静态方法来获取上线文。

package com.sun.applicationContextAware.intf;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

//@Component 去掉注解,直接配置在spring上下文文件中
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    /**
     * 这个接口的就是帮助我们的程序获取spring的 上下文的,如何获取呢 我们需要定义一个 ApplicationContext 的上下文
     * 思考细节:setApplicationContext 是什么时候被调用的???
     * @param applicationContext
     * @throws BeansException
     */

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

    /**
     * 写一个方法 来获取 applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

}

 

2.编写spring上下文xml文件,越简单越好,这里我们只配置了一个

通过注解@Component方式,applicationContext有时会为null的问题解决方法?
这时我们就可以不用注解的方式直接在Spring的配置文件applicationContext.xml中单独配置这个bean并且把他放在包扫描之前.SpringContextUtil类,由于加载顺序的问题如果只依靠注解来加载,有可能setApplicationContext方法 还没执行,导致我们获取的applicationContext获取的属性对象为空,所以配置在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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="springContextUtil" class="com.sun.applicationContextAware.intf.SpringContextUtil"></bean>

</beans>

3.编写测试基类,用来加载配置,注意需要加@RunWith和@ContextConfiguration两个注解 ,一个是使用spring集成的JUnit 另一个是 指定加载的上下问文件

package com.sun.base;

import com.sun.applicationContextAware.intf.SpringContextUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext.xml"})
public class SpringBaseTest {
// 可以写一些基类需要处理的事情
}

4.最终写测试文件,继承基类,打印只要获取到上下文,下面想获取任何bean都可以了

package com.sun.test;

import com.sun.applicationContextAware.intf.SpringContextUtil;
import com.sun.base.SpringBaseTest;
import org.junit.Test;

public class ApplicationContextAwareTest extends SpringBaseTest {

    @Test
    public void testSpringContextUtil(){
       ApplicationContext ctx = SpringContextUtil.getApplicationContext();
       System.out.println("==================" + ctx);
       //使用这种方式获取bean,ctx.getBean("beanId");
    }

}

那么ApplicationContextAware的setApplicationContext方法是什么时候执行的?

从图中可以看出,最后会调用initializeBeanf方法又会调用applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization方法,也就是调用bean后处理器,bean后处理器其中就有一个叫ApplicationContextAwareProcessor,其中的处理方法如下代码,就有调用到setApplicationContext方法,部分源码如下:

@Override
    @Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            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);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

你是不是会问ApplicationContextAwareProcessor什么时候放到容器中的,看org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory方法中就放进来了 

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        ······
    }

prepareBeanFactory又在org.springframework.context.support.AbstractApplicationContext#refresh方法中被调用,看是不是又回到容器初始化的入口了,整个流程是不是打通了

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值