㈠ Spring配置文件中如何注入另一个XML中的配
主要有两种方式:
1、在一个配置文件中使用import标签导入其他配置文件,即
applicationContext.xml中部分代码如下:<import resource="applicationContext-.xml" /><import resource="applicationContext-service.xml" /><import resource="applicationContext-action.xml" />
2、在web.xml中配置Spring配置文件处导入多个配置文件,即可
a、导入多个配置文件
web.xml部分代码如下:<context-param> <param-name>contextConfigLocation</param-name> <param-value> applicationContext-core.xml, applicationContext-.xml, applicationContext-service.xml, applicationContext-action.xml </param-value></context-param>
b、使用*通配符导入多个配置文件
web.xml部分代码如下:<context-param> <param-name>contextConfigLocation</param-name> <param-value> applicationContext-*.xml </param-value></context-param>
㈡ spring 配置文件的bean自动注入失败的解决方法是什么
一个Spring注入问题,首先看一个普通Spring Bean,
publicclassFoo{
@Autowired
Barbar;
publicvoiddoSomething(){
bar.doSomething();
}
}
Spring配置一:
<beanid="bar"class="com.test.Bar"></bean>
<beanid="foo"class="com.test.Foo"></bean>
单元测试:
@Test
publicvoidtest_doSomthing(){
ApplicationContextctx=("applicationContext-test.xml");
Foofoo=ctx.getBean(Foo.class);
foo.doSomething();
}
执行上述测试方法,报错
java.lang.NullPointerException
atcom.test.Foo.doSomething(Foo.java:15)
atcom.test.FooTest.test_doSomthing(FooTest.java:13)
即foo bean中的bar并未注入。
Spring配置二:
<context:component-scanbase-package="com.test"></context:component-scan>
当改成配置二后执行上述单元测试方法便能成功通过。经分析日志及查看源代码,发现使用配置二时供装载了6个bean,如下所示:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]
DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)Beanfactoryfororg.springframework.context.support.@3c4e80d3:org.springframework.beans.factory.support.DefaultListableBeanFactory@14cc51c8:definingbeans[bar,foo,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.];rootoffactoryhierarchy
而使用配置一时只有两个bean,如下所示:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]
DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)Beanfactoryfororg.springframework.context.support.@45ebbb93:org.springframework.beans.factory.support.DefaultListableBeanFactory@18481697:definingbeans[bar,foo];rootoffactoryhierarchy
配置二执行单元测试通过的原因似乎就在于多出的这几个bean。是不是只要有context:component-scan元素在自动就会有这几个bean的产生?验证此假设
在配置一中添加一个无实际意义的context:component-scan元素,如下所示:
<context:component-scanbase-package="com.nonexist"></context:component-scan>
这时执行单元测试能通过,同配置二一样也会装载6个bean。那么这6个bean中到底哪个对注入bar到Foo中起了作用呢?
经过断点调试发现是 bean起了作用,见输出日志:
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60)Foundinjectedelementonclass[com.test.Foo]:AutowiredFieldElementforcom.test.Barcom.test.Foo.bar
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85)'foo':AutowiredFieldElementforcom.test.Barcom.test.Foo.bar
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245)'bar'
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.annotation..registerDependentBeans(.java:424)Autowiringbytypefrombeanname'foo'tobeannamed'bar'
2015-04-2520:23:09DEBUGorg.springframework.beans.factory.support..createBean(.java:458)'foo'
那么直接在配置一种显式添加bean呢?如下所示:
<beanid="bar"class="com.tcl.account.service.test.Bar"></bean>
<beanid="foo"class="com.tcl.account.service.test.Foo"></bean>
<beanid=""class="org.springframework.beans.factory.annotation."></bean>
测试会不会通过?会通过。见日志:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[applicationContext-test.xml]
DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)Beanfactoryfororg.springframework.context.support.@7767d3c1:org.springframework.beans.factory.support.DefaultListableBeanFactory@1924ed52:definingbeans[bar,foo,];rootoffactoryhierarchy
DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.<init>(InjectionMetadata.java:60)Foundinjectedelementonclass[com.test.Foo]:AutowiredFieldElementforcom.test.Barcom.test.Foo.bar
DEBUGorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:85)'foo':AutowiredFieldElementforcom.test.Barcom.test.Foo.bar
DEBUGorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245)'bar'
DEBUGorg.springframework.beans.factory.annotation..registerDependentBeans(.java:424)Autowiringbytypefrombeanname'foo'tobeannamed'bar'
DEBUGorg.springframework.beans.factory.support..createBean(.java:458)'foo'
那么为什么在配置文件中添加了context:componet-scan元素后就会自动添加那另外4个bean呢?经过断点调试发现Spring隐式装载的4个bean是在如下方法中加载的:
Set<BeanDefinitionHolder>org.springframework.context.annotation.AnnotationConfigUtils.(,Objectsource)
其调用链如下所示:
补充一:
若仍用配置一,但单元测试改成如下形式也可以测试通过。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/applicationContext-test.xml"})
publicclassFooTest2{
@Autowired
privateFoofoo;
@Test
publicvoidtest_doSomthing(){
foo.doSomething();
}
}
当然一点都不意外,这种方式也会隐式加载那4个bean,见日志:
DEBUGorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216)[classpath:/applicationContext-test.xml]
INFOorg.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:500)Refreshingorg.springframework.context.support.GenericApplicationContext@51f3336e:startupdate[SunApr2617:27:35CST2015];rootofcontexthierarchy
DEBUGorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:530)Beanfactoryfororg.springframework.context.support.GenericApplicationContext@51f3336e:org.springframework.beans.factory.support.DefaultListableBeanFactory@4f9d1352:definingbeans[bar,foo,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.,org.springframework.context.annotation.];rootoffactoryhierarchy
补充二,若使用的是@Value,效果同@Autowired,即也需要隐式加载 bean。
publicclassFoo{
@Value("${bar}")
Stringbar;
publicvoiddoSomething(){
System.out.println(bar);
}
}
补充三:
若使用配置一,@PostConstruct标注的方法也不会被执行,但此时需要隐式加载的Spring bean是:org.springframework.context.annotation.
补充四:
在配置一中添加如下配置
<context:annotation-config/>
也会隐式加载那4个bean
㈢ 怎么创建junit4 注入spring 配置文件
1 建立一个test的目录,在此目录下放置所有的JunitTestCase类和TestCase的配置文件
2 将项目中的Spring配置文件(默认名称为applicationContext.xml)复制到test目录下,并重新命名为JunitTestConf.xml。
3 根据Junit测试的需要修改JunitTestConf.xml文件中的内容,如数据库连接等。
4 新建一个名为SpringConfForTest.java的类,在此类中配置Spring启动所需的配置文件,并启动Spring。此类的内容如下:
package test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.;
import com.soma.global.WebContextHolder;
public class SpringConfForTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
//Spring启动所需要的配置参数文件,其中test/JunitTestConf.xml文件中保存了数据库连接等参数,可根据具体情况做修改
String[] paths = new String[] {"test/JunitTestConf.xml", "com/soma/conf/applicationContext--hr.xml","com/soma/conf/applicationContext-.xml","com/soma/conf/applicationContext--bug.xml","com/soma/conf/applicationContext--change.xml","com/soma/conf/applicationContext--common.xml","com/soma/conf/applicationContext-service-hr.xml" };
//启动Spring,得到Spring环境上下文
ApplicationContext ctx = new (paths);
//在此类启动时,将Spring环境上下文保存到单根类WebContextHolder中,以提供给其它的测试类使用
WebContextHolder.getInstence().setApplicationContext(ctx);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Test
public void test(){
//必须要写一个test空方法,否则SpringConfForTest类不会启动
}
}
5 新建TestSuite类,类名为AllTests,类的内容如下所示:
package test;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import test.com.soma.domain.busilogic.hr.HrBusiLogicTest;
import test.com.soma.domain.service.hr.checkOverTimeDateTest;
@RunWith(Suite.class)
@Suite.SuiteClasses({
SpringConfForTest.class,
HrBusiLogicTest.class,
checkOverTimeDateTest.class
})
/**
* 批量执行Junit测试类,把类名写入到上面的Suite.SuiteClasses({})中,用逗号分隔
*/
public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("Test for test");
//$JUnit-BEGIN$
//$JUnit-END$
return suite;
}
}
注意:将SpringConfForTest.class放在第一个执行,以启动Spring配置环境,把自己的TestCase类放到后面,用逗号分开。在测试时,只要执行这个TestSuite类就可以了。
6 写自己的TestCase类,以CheckOverTimeDateTest.java为例子,文件内容如下:
public class CheckOverTimeDateTest {
private static HrTbovertimeManager hrTbovertimeManager;
private static ExcuteSqlDAO excuteSqlDAO;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
//从Spring上下文中得到hrTbovertimeManager接口类的实例
hrTbovertimeManager=(HrTbovertimeManager)BeanUtil.getBean("hrTbovertimeManager");
excuteSqlDAO = (ExcuteSqlDAO) BeanUtil.getBean("excuteSqlDAO");
}
@Test
public void testGetProjectList()throws Exception {
List<OvertimeDetailValue> overtimeDetailValueList = new ArrayList<OvertimeDetailValue>();
int index = 9;
for(int i = 1 ;i <= index;i++){
OvertimeDetailValue overtimeDetailValue = new OvertimeDetailValue();
overtimeDetailValue.setOtApplyDate("2009-05-0"+i);
overtimeDetailValueList.add(overtimeDetailValue);
}
String resultStr = hrTbovertimeManager.checkOverTimeDate(overtimeDetailValueList);
assertEquals("false", resultStr);
}
/**
* 导入2009-03月份出勤记录excel文件,返回null表示导入成功,需要先删除3月份的数据
*/
@Test
public void testSaveExcelDutyInformation() throws Exception{
// 在导入3月份出勤记录前先删除3月份的记录,执行delete from hr_tbtyinformation;
excuteSqlDAO.excuteSql("delete from hr_tbtyinformation where tydate>='2009-02-26' and tydate<='2009-03-25'");
// System.out.println("----------"+System.getProperty("user.dir")+"/src/test/ty200903.xls");
String fileName = System.getProperty("user.dir")
+ "/src/test/ty200903.xls";
assertNull(hrTbtyInformationManager.saveExcelDutyInformation(fileName));
}
}
说明:BeanUtil.getBean("")相当于WebContextHolder.getInstence().getApplicationContext().getBean(""),只是对此方法做了封装。
7 在Eclipse中,启动AllTests,选择“Run As JunitTest”,即可先启动Spring环境,再依次运行你自己所写的JunitTestCase,是不是很简单哪?赶快动手试试吧。