配色: 字号:
Spring实战——通过Java代码装配bean
2017-01-19 | 阅:  转:  |  分享 
  
Spring实战——通过Java代码装配bean



基于注解的自动化注入固然优雅,但是它也有鞭长莫及的时候,这时候就来看看Java代码如何装配bean的。



还记的上篇的配置类CDPlayerConfig是长这样的





@Configuration

@ComponentScan

publicclassCDPlayerConfig{

}

有了这个万能的组件扫描注解,一切都是那么只能,只需要在bean类上加上如@Component注解,Spring就会自动为该类创建相应的bean类。



但是现在因为我们有一些第三方类库,我们没办法去深入类中加上这些标记了,所以@ComponentScan就失去了威力和意义。







这篇的CDPlayerConfig应该长这样





@Configuration

publicclassCDPlayerConfig{

}

@Configuration注解表示该类是一个配置类。显然要创建的bean的信息是要放到这个类中的。



基于其他类以及类中的方法不变比如CompactDisc,CDPlayer,SgtPeppers等。编写测试方法如下



@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes=CDPlayerConfig.class)

publicclassCDPlayerTest{



@Rule

publicfinalStandardOutputStreamLoglog=newStandardOutputStreamLog();



@Autowired

privateMediaPlayerplayer;



@Autowired

privateCompactDisccd;



@Test

publicvoidcdShouldNotBeNull(){

assertNotNull(cd);

}



@Test

publicvoidplay(){

player.play();

assertEquals(

"PlayingSgt.Pepper''sLonelyHeartsClubBandbyTheBeatles\r\n",

log.getLog());

}



}





首先从代码来看就会出现如下的注入错误











这里显示MediaPlayer无法注入。同时运行程序得到结果如下



Testingstartedat0:20...

0:20:03:Executingexternaltasks''cleanTesttest''...

:cleanTest

:compileJava

:processResourcesUP-TO-DATE

:classes

:compileTestJava

:processTestResourcesUP-TO-DATE

:testClasses

:test

一月15,201712:20:06上午org.springframework.test.context.TestContextManagerretrieveTestExecutionListeners

信息:CouldnotinstantiateTestExecutionListener[org.springframework.test.context.web.ServletTestExecutionListener].Specifycustomlistenerclassesormakethedefaultlistenerclasses(andtheirrequireddependencies)available.Offendingclass:[javax/servlet/ServletContext]

一月15,201712:20:06上午org.springframework.test.context.TestContextManagerretrieveTestExecutionListeners

信息:CouldnotinstantiateTestExecutionListener[org.springframework.test.context.transaction.TransactionalTestExecutionListener].Specifycustomlistenerclassesormakethedefaultlistenerclasses(andtheirrequireddependencies)available.Offendingclass:[org/springframework/transaction/interceptor/TransactionAttributeSource]

一月15,201712:20:06上午org.springframework.context.support.GenericApplicationContextprepareRefresh

信息:Refreshingorg.springframework.context.support.GenericApplicationContext@6adf0b01:startupdate[SunJan1500:20:06CST2017];rootofcontexthierarchy

一月15,201712:20:06上午org.springframework.test.context.TestContextManagerprepareTestInstance

严重:CaughtexceptionwhileallowingTestExecutionListener[org.springframework.test.context.support.DependencyInjectionTestExecutionListener@61c715e8]topreparetestinstance[soundsystem.CDPlayerTest@1081b08c]

org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname''soundsystem.CDPlayerTest'':Injectionofautowireddependenciesfailed;nestedexceptionisorg.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatesoundsystem.MediaPlayersoundsystem.CDPlayerTest.player;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:293)

atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)

atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:384)

atorg.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)

atorg.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)

atorg.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:331)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:213)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:290)

atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:292)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)

atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)

atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)

atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)

atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)

atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)

atorg.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)

atorg.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)

atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:105)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:56)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)

atorg.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)

atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)

atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

atjava.lang.reflect.Method.invoke(Method.java:497)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

atorg.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)

atorg.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)

atcom.sun.proxy.$Proxy2.processTestClass(UnknownSource)

atorg.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)

atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)

atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

atjava.lang.reflect.Method.invoke(Method.java:497)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

atorg.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)

atorg.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)

atorg.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)

atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

atjava.lang.Thread.run(Thread.java:745)

Causedby:org.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatesoundwww.tt951.comsystem.MediaPlayersoundsystem.CDPlayerTest.player;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:509)

atorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:290)

...46more

Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1118)

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:481)

...48more





Errorcreatingbeanwithname''soundsystem.CDPlayerTest'':Injectionofautowireddependenciesfailed;nestedexceptionisorg.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatesoundsystem.MediaPlayersoundsystem.CDPlayerTest.player;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname''soundwww.baiyuewang.netsystem.CDPlayerTest'':Injectionofautowireddependenciesfailed;nestedexceptionisorg.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatesoundsystem.MediaPlayersoundsystem.CDPlayerTest.player;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:293)

atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)

atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:384)

atorg.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)

atorg.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)

atorg.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:331)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:213)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:290)

atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:292)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)

atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)

atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)

atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)

atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)

atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)

atorg.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)

atorg.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)

atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)

atorg.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:105)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:56)

atorg.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)

atorg.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)

atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)

atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

atjava.lang.reflect.Method.invoke(Method.java:497)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

atorg.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)

atorg.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)

atcom.sun.proxy.$Proxy2.processTestClass(UnknownSource)

atorg.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)

atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)

atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

atjava.lang.reflect.Method.invoke(Method.java:497)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)

atorg.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)

atorg.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)

atorg.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)

atorg.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)

atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

atjava.lang.Thread.run(Thread.java:745)

Causedby:org.springframework.beans.factory.BeanCreationException:Couldnotautowirefield:privatesoundsystem.MediaPlayersoundsystem.CDPlayerTest.player;nestedexceptionisorg.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:509)

atorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:290)

...46more

Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException:Noqualifyingbeanoftype[soundsystem.MediaPlayer]foundfordependency:expectedatleast1beanwhichqualifiesasautowirecandidateforthisdependency.Dependencyannotations:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1118)

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)

atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)

atorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:481)

...48more



soundsystem.CDPlayerTest>playFAILED

org.springframework.beans.factory.BeanCreationException

Causedby:org.springframework.beans.factory.BeanCreationException

Causedby:org.springframework.beans.factory.NoSuchBeanDefinitionException

1testcompleted,1failed

:testFAILED

FAILURE:Buildfailedwithanexception.

Whatwentwrong:

Executionfailedfortask'':test''.

>Therewerefailingtests.Seethereportat:file:///C:/Users/Administrator/Desktop/spring_video/SpringiA4_SourceCode/Chapter_02/stereo-javaconfig/build/reports/tests/index.html

Try:

Runwith--stacktraceoptiontogetthestacktrace.Runwith--infoor--debugoptiontogetmorelogoutput.

BUILDFAILED

Totaltime:4.59secs

Therewerefailingtests.Seethereportat:file:///C:/Users/Administrator/Desktop/spring_video/SpringiA4_SourceCode/Chapter_02/stereo-javaconfig/build/reports/tests/index.html

究其原因,主要是既没有在xml中没有声明相应的bean,也没有添加@ComponentScan启动自动扫描组件机制。



所以这里还是需要在CDPlayerConfig配置类中做文章。







声明bean



通过注解@Bean声明一个bean对象。



@Bean

publicCompactDisccompactDisc(){

returnnewSgtPeppers();

}

该声明好比在xml中添加



1



通过这种方式,Spring会默认为SgtPeppers创建一个名为sgtPeppers的bean,如果你想换个名字,只需要在@Bean后面加上类似(name="lonelyHeartClubBand")这样的属性即可。







如果你的野心远不止满足于通过Java代码创建一个bean的话,其实你还试试如何在CDPlayer中播放CompactDisc,那就需要在CDPlayer中注入CompactDisc的bean了。于是我们可以这样声明





@Bean

publicCDPlayercdPlayer(CompactDisccompactDisc){

returnnewCDPlayer(compactDisc);

}

加上@Bean注解,表明cdPlayer()方法会创建一个bean实例并将其注册到Spring的应用上下文中,显然bean的名字默认就是cdPlayer。在执行这个方法的时候,Spring会拦截所有对方法的调用,当然这里会传入Spring注册好的CompactDisc的实例bean给cdPlayer方法来确保返回的是创建好的cdPlayer的bean。注意这里的bean是单例的,其实在xml中配置的bean如果没有特殊声明,默认也是单例的。也就是说即使这里创建了多个类似cdPlayer的方法,得到的仍然是同一个cdPlayer的bean。







这时候运行测试类CDPlayerTest



@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes=CDPlayerConfig.class)

publicclassCDPlayerTest{



@Rule

publicfinalStandardOutputStreamLoglog=newStandardOutputStreamLog();



@Autowired

privateMediaPlayerplayer;



@Test

publicvoidplay(){

player.play();

assertEquals(

"PlayingSgt.Pepper''sLonelyHeartsClubBandbyTheBeatles\r\n",

log.getLog());

}



献花(0)
+1
(本文系thedust79首藏)