Spring 父類變量注入失敗的解決
Spring 父類變量注入失敗
昨天遇到一個(gè)Action里面Service注入失敗,換種說(shuō)法應(yīng)該說(shuō)是根本沒有發(fā)生注入,本來(lái)很簡(jiǎn)單的一個(gè)問題,但由于在項(xiàng)目中多個(gè)Action進(jìn)行了繼承,才最終導(dǎo)致了這個(gè)看似奇怪的問題。
下面小記下這個(gè)過程
收到同事問題,“有個(gè)Action請(qǐng)求一直調(diào)用報(bào)控指針,service一直是空的導(dǎo)致的!”
初步看了代碼及配置,沒有發(fā)現(xiàn)什么問題,起初懷疑是Action沒有g(shù)et方法所致,然后加上仍然無(wú)效;然后單步做了各種變量名的替換,一直一樣問題 ,這過程中一直關(guān)注java代碼確忽略了頁(yè)面請(qǐng)求,通過頁(yè)面請(qǐng)求發(fā)現(xiàn)代碼真正邏輯是頁(yè)面請(qǐng)求了一個(gè)子類Action的方法,而這個(gè)方法里面調(diào)用了父類的一個(gè)方法,此時(shí)父類里面的Service一直無(wú)法注入,對(duì)于上面所提的這種需求,實(shí)際上是需要在子類做Spring注入的同時(shí)也進(jìn)行父類的Spring注入,那么這種需要這樣的配置:
<bean id="****Action" class="com.**.**.contrl.**.mgr.action.**Action" scope="prototype" parent="termCommonAction"> <property name="orderVerifyApiFacade" ref="ord.bizprov.orderVerifyApiFacade"/> <property name="orderListQryApiFacade" ref="ord.query.orderListQryApiFacade"/> <property name="channelQryApiFacade" ref="cfguse.channel.channelQryApiFacade" /> </bean>
經(jīng)過上面的設(shè)置以后,請(qǐng)求子類的Action方法,子類方法中調(diào)用父類方法時(shí),就不會(huì)出現(xiàn)父類不發(fā)生注入的問題了。
Spring通過父類注入公用屬性的技巧
XML配置方式提取父類
在使用Spring + Hibernate框架,或者SSH2等框架的時(shí)候,在開發(fā)中只有一個(gè)基本的DAO是現(xiàn)在的非常流行的做法。然后,在看過多份這種代碼以后,都是在每個(gè)業(yè)務(wù)類中聲明了一個(gè)DAO屬性,并且在Bean配置中,對(duì)每個(gè)業(yè)務(wù)類分別注入DAO。具體情形示例如下:
BaseDAO代碼:
public class BaseDAO { public String service() { return "Success!"; } }
Services代碼:
//第一個(gè)業(yè)務(wù)類 public class ServiceA { public String service() { return baseDAO.service(); } protected BaseDAO baseDAO; public void setBaseDAO(BaseDAO baseDAO) { this.baseDAO = baseDAO; } } //第二個(gè)業(yè)務(wù)類 public class ServiceB { public String service() { return baseDAO.service(); } protected BaseDAO baseDAO; public void setBaseDAO(BaseDAO baseDAO) { this.baseDAO = baseDAO; } }
Spring的Bean配置如下:
<bean id="baseDAO" class="com.watson.BaseDAO" /> <bean id="serviceA" class="com.watson.ServiceA"> <property name="baseDAO" ref="baseDAO" /> </bean> <bean id="serviceB" class="com.watson.ServiceB"> <property name="baseDAO" ref="baseDAO" /> </bean>
這樣的做法是現(xiàn)在的主流。這樣做不是說(shuō)那里錯(cuò)了,還是那句老話:這樣做肯定不優(yōu)美,誰(shuí)讓人有時(shí)候是一根筋呢?
能夠想到的辦法是用一個(gè)父類來(lái)包含一些業(yè)務(wù)層公用的業(yè)務(wù)邏輯和屬性。所以可以將上面的代碼和配置。
Services代碼改寫如下:
//所有業(yè)務(wù)類的父類 public class BaseService { protected BaseDAO baseDAO; public void setBaseDAO(BaseDAO baseDAO) { this.baseDAO = baseDAO; } } //第一個(gè)業(yè)務(wù)類 public class ServiceA extends BaseService { public String service() { return baseDAO.service(); } } //第二個(gè)業(yè)務(wù)類 public class ServiceB extends BaseService { public String service() { return baseDAO.service(); } }
Spring的Bean配置改寫如下:
<bean id="baseDAO" class="com.watson.BaseDAO" /> <bean id="BaseService" class="com.watson.BaseService" /> <property name="baseDAO" ref="baseDAO" /> </bean> <bean id="serviceA" class="com.watson.ServiceA" /> <bean id="serviceB" class="com.watson.ServiceB" />
這樣一來(lái)是不簡(jiǎn)潔了很多?尤其在實(shí)際項(xiàng)目有太多Bean的時(shí)候。然后,這里不會(huì)達(dá)到我們預(yù)想的結(jié)果,因?yàn)檫@里會(huì)出現(xiàn)如下的錯(cuò)誤:
exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is
java.lang.NullPointerException
......
root cause:
java.lang.NullPointerException:......
而出錯(cuò)代碼就是每個(gè)業(yè)務(wù)中調(diào)用baseDAO的那行代碼。這說(shuō)明注入失敗了。翻閱Spring的Bean注入詳解之后,很快就可以找應(yīng)該設(shè)置子類Bean配置的parent屬性。所以這里可以修改設(shè)置。
Spring的Bean配置改寫如下:
<bean id="baseDAO" class="com.watson.BaseDAO" /> <bean id="BaseService" class="com.watson.BaseService" /> <property name="baseDAO" ref="baseDAO" /> </bean> <bean id="serviceA" class="com.watson.ServiceA" parent="baseService" /> <bean id="serviceB" class="com.watson.ServiceB" parent="baseService" />
這個(gè)時(shí)候再運(yùn)行,就不會(huì)報(bào)錯(cuò)了。原理是:在Spring的子類Bean配置中,其parent屬性作用是指定其父類,并繼承父類的注入屬性。不僅如此,子類還可以修改或者覆蓋父類的屬性值。例如上述代碼中的子類修改父類的baseDAO到屬性:
<bean id="BaseService" class="com.watson.BaseService" /> <property name="baseDAO" ref="baseDAO" /> </bean> <bean id="serviceA" class="com.watson.ServiceA" parent="baseService" /> <property name="baseDAO" ref="baseDAO2" /> </bean>
而對(duì)于父類的List等集合屬性,子類可以繼承父類的值,并且在其基礎(chǔ)上進(jìn)行增加新的值:
<bean id="BaseService" class="com.watson.BaseService" /> <property name="listValue"> <list> <value>listValue1</value> <value>listValue2</value> </list> </property> </bean> <bean id="serviceA" class="com.watson.ServiceA" parent="baseService" /> <property name="listValue"> <list> <value>listValue3</value> <value>listValue4</value> </list> </property> </bean>
Annotation方式提取父類
上面的方法是在XML配置文件中進(jìn)行的配置。而對(duì)現(xiàn)在Spring3流行的Annotation方式,其實(shí)更加的方便,完整示例如下:
BaseDAO代碼:
@Component public class BaseDAO { public String service() { return "Success!"; } }
Services代碼:
//所有業(yè)務(wù)類的父類 public class BaseService { @Autowired protected BaseDAO baseDAO; } //第一個(gè)業(yè)務(wù)類 @Component public class ServiceA extends BaseService { public String service() { return baseDAO.service(); } } //第二個(gè)業(yè)務(wù)類 @Component public class ServiceB extends BaseService { public String service() { return baseDAO.service(); } }
Action層代碼:
@Controller @RequestMapping(value = "/testaction") public class TestAction { @Autowired private ServiceA service; @RequestMapping(value = "/") public @ResponseBody String home(Model model) { return service.service(); } }
這里根本就不需要進(jìn)行parent屬性子類的配置,可以完美的提取父類,并且可以順利的使用父類的公用屬性。至于原理,沒有去看源碼的處理方式,估計(jì)和上述XML配置是異曲同工的,只是在這里增加了對(duì)父類的檢測(cè)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于try 和 throw 簡(jiǎn)單使用示例
每過一段時(shí)間,就總是會(huì)對(duì)try有點(diǎn)生疏,特別寫了個(gè)程序來(lái)測(cè)試以下,有時(shí)候 throw是底層拋出來(lái)的,你不處理,默認(rèn)就throw了2013-08-08使用list stream:對(duì)List中的對(duì)象先進(jìn)行排序再獲取前n個(gè)對(duì)象
這篇文章主要介紹了使用list stream:對(duì)List中的對(duì)象先進(jìn)行排序再獲取前n個(gè)對(duì)象,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09基于SpringBoot與Mybatis實(shí)現(xiàn)SpringMVC Web項(xiàng)目
這篇文章主要介紹了基于SpringBoot與Mybatis實(shí)現(xiàn)SpringMVC Web項(xiàng)目的相關(guān)資料,需要的朋友可以參考下2017-04-04SpringMVC源碼之HandlerMapping處理器映射器解析
這篇文章主要介紹了SpringMVC源碼之HandlerMapping處理器映射器解析,在Spring?MVC中,HandlerMapping處理器映射器用于確定請(qǐng)求處理器對(duì)象,請(qǐng)求處理器可以是任何對(duì)象,只要它們使用了@Controller注解或注解@RequestMapping,需要的朋友可以參考下2023-08-08idea創(chuàng)建maven項(xiàng)目速度慢的三種解決方案
這篇文章主要介紹了idea創(chuàng)建maven項(xiàng)目速度慢的三種解決方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2019-01-01SpringBoot遠(yuǎn)程訪問redis服務(wù)器問題剖析
使用了SpringBoot的項(xiàng)目,在遠(yuǎn)程連接Redis服務(wù)器時(shí),會(huì)遇倒一些小問題,下面通過本文給大家全面解析SpringBoot遠(yuǎn)程訪問redis服務(wù)器問題,需要的朋友參考下吧2017-04-04