1. 程式人生 > >記一次mybatis的classpath踩坑記錄

記一次mybatis的classpath踩坑記錄

前情提要:

某日,M君外出辦事,結果去早了,店家未開門。
見寒風凜冽,遂溜進一網咖。開啟電腦欲大戰機器人一把。
結果看到群內某男問了一個springmvc問題,M君按耐不住。欲解之,故有了下文。。。

問題描述:

環境:Spring+SpringMVC+Mybatis,Maven構建
異常:Install時,

[org.springframework.test.context.TestContextManager]Caught exception while allowing TestExecutionListener [org.springframework.test.context
.web.ServletTestExecutionListener@4a4038e2] to prepare test instance [sy.test.TestMybatis@6e030872] java.lang.IllegalStateException: Failed to load ApplicationContext

起初一眼認定 ,測試用例TestMybatis裡面的spring.xml路徑配置錯了。
於是你來我往聊了半天,沒說出個所以然。再加上對maven不是非常熟悉,於是去看了看maven方面spring.xml配置檔案的路徑問題,發現應該是對的。
又問: service註解寫了沒啊?scan service的spring xml檔案是哪個啊,有問有給進去啊?都沒問題。
這下有點摸不著頭腦了。

思索一小會兒,讓其把完整異常發來。開啟檔案的瞬間一萬個尼瑪飛過。
大哥,你TM發異常能發完整不?
你可知道這會整死人不?
這裡寫圖片描述

[org.springframework.test.context.TestContextManager]Caught exception while allowing TestExecutionListener [or[email protected]4a4038e2] to prepare test instance [[email protected]6e030872]
java.lang.IllegalStateException: Failed to
load ApplicationContext at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:103) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:73) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:146) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) at com.sun.proxy.$Proxy0.invoke(Unknown Source) at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:145) at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:87) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void sy.service.UserServiceImpl.setUserMapper(sy.dao.UserMapper); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [sy.dao.UserMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRoleMapper' defined in file [U:\Spring\testmybatis\target\classes\sy\dao\UserRoleMapper.class]: Cannot resolve reference to bean 'sqlSessionFactory' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring-mybatis.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.core.io.Resource[]' for property 'mapperLocations'; nested exception is java.lang.IllegalArgumentException: Could not resolve resource location pattern [classpath:sy/mapping/*.xml]: class path resource [sy/mapping/] cannot be resolved to URL because it does not exist

class path resource [sy/mapping/] cannot be resolved to URL because it does not exist
看完之後,立馬認定還是路徑不對,但是是sy/mapping/這個不對,而不是spring.xml,於是問這是什麼玩意兒?
答:mybatis配置檔案。

於是索要了專案結構圖:
這裡寫圖片描述

研究了半天,沒發現啥錯啊。
於是準備在網咖整個IDE編譯看看。結果破網咖的網速不到500K。誰TM在下片啊。(吐槽下:自稱網咖,卻濃濃的煙味)

奈何還有急事在身,於是匆忙出了網咖,去辦事了。

半小時後,回到辦公室,要了份專案壓縮包,就Happy的跑起來了。
研究了一會兒,沒什麼頭緒,感覺什麼都是對的。
思來想去,算了,換個路徑,不是說maven推薦resources放資原始檔嘛,那就把這些mapping丟resources原始檔夾下。
Bingo!Success了。我了個去,百度了下,沒這方面的情報。只有之後再研究研究了。
這裡寫圖片描述

收穫:

其實一直對classpath這個玩意兒一知半解,迷迷糊糊的。通過這次我對它認識更深了一步。

之前的印象:
在src目錄下建個resources資料夾,丟配置檔案.然後classpath:resources即可。
然後就是WEB-INF下的會自動被讀取到。

現在:
看目錄結構!source folder,和folder,還有package是有很大區別的!
按之前的理解,MybatisMapper下的mapper寫法是:classpath:main/resources/MybatisMapper/*.xml
現在看來完全就是錯誤的,應該是classpath:MybatisMapper/*.xml
意思就是我們應該是按照原始檔夾下的路徑來寫。(如果有錯誤或者不足歡迎指正,本人也是在學習)
(之後好好理解下原始檔夾、資料夾、package的區別)

以及:
專案一定要按結構來劃分,資原始檔不要放在程式碼的package裡面,那樣是讀不到的
(或者有方法能讀到,但是肯定不如清晰的結構來得好)

其他:
classpath:/xxx 和 classpath:xxx是一樣的
classpath:xxx 和 classpath*:xxx是不一樣的,前者表示引入一個,後者表示引入多個。

其實我經常喜歡回答群里人問的問題,可能很多大神完全不屑於回答。但是對我這菜鳥來說,能在解答的過程中重新學習認識一遍。是一種很有效的學習/複習方法。而且從他人的程式碼/問題中能學習到很多我所沒遇到的問題和知識。

想我當年高中意氣風發時候,物理課從不聽講,書一直沒翻過,只有等到妹子們來問我這個物理課代表課後題目的時候,我才臨時抱佛腳,看一通,然後做出來給她們講。現在看來,這方法到現在還適用啊!哈哈!所以說做題實踐永遠比死記硬背來的快也來的懂!