您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Spring父類變量注入失敗怎么辦,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
昨天遇到一個Action里面Service注入失敗,換種說法應該說是根本沒有發生注入,本來很簡單的一個問題,但由于在項目中多個Action進行了繼承,才最終導致了這個看似奇怪的問題。
收到同事問題,“有個Action請求一直調用報控指針,service一直是空的導致的!”
初步看了代碼及配置,沒有發現什么問題,起初懷疑是Action沒有get方法所致,然后加上仍然無效;然后單步做了各種變量名的替換,一直一樣問題 ,這過程中一直關注java代碼確忽略了頁面請求,通過頁面請求發現代碼真正邏輯是頁面請求了一個子類Action的方法,而這個方法里面調用了父類的一個方法,此時父類里面的Service一直無法注入,對于上面所提的這種需求,實際上是需要在子類做Spring注入的同時也進行父類的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>
經過上面的設置以后,請求子類的Action方法,子類方法中調用父類方法時,就不會出現父類不發生注入的問題了。
在使用Spring + Hibernate框架,或者SSH2等框架的時候,在開發中只有一個基本的DAO是現在的非常流行的做法。然后,在看過多份這種代碼以后,都是在每個業務類中聲明了一個DAO屬性,并且在Bean配置中,對每個業務類分別注入DAO。具體情形示例如下:
BaseDAO代碼:
public class BaseDAO { public String service() { return "Success!"; } }
Services代碼:
//第一個業務類 public class ServiceA { public String service() { return baseDAO.service(); } protected BaseDAO baseDAO; public void setBaseDAO(BaseDAO baseDAO) { this.baseDAO = baseDAO; } } //第二個業務類 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>
這樣的做法是現在的主流。這樣做不是說那里錯了,還是那句老話:這樣做肯定不優美,誰讓人有時候是一根筋呢?
能夠想到的辦法是用一個父類來包含一些業務層公用的業務邏輯和屬性。所以可以將上面的代碼和配置。
Services代碼改寫如下:
//所有業務類的父類 public class BaseService { protected BaseDAO baseDAO; public void setBaseDAO(BaseDAO baseDAO) { this.baseDAO = baseDAO; } } //第一個業務類 public class ServiceA extends BaseService { public String service() { return baseDAO.service(); } } //第二個業務類 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" />
這樣一來是不簡潔了很多?尤其在實際項目有太多Bean的時候。然后,這里不會達到我們預想的結果,因為這里會出現如下的錯誤:
exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is
java.lang.NullPointerException
......
root cause:
java.lang.NullPointerException:......
而出錯代碼就是每個業務中調用baseDAO的那行代碼。這說明注入失敗了。翻閱Spring的Bean注入詳解之后,很快就可以找應該設置子類Bean配置的parent屬性。所以這里可以修改設置。
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" />
這個時候再運行,就不會報錯了。原理是:在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>
而對于父類的List等集合屬性,子類可以繼承父類的值,并且在其基礎上進行增加新的值:
<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>
上面的方法是在XML配置文件中進行的配置。而對現在Spring3流行的Annotation方式,其實更加的方便,完整示例如下:
BaseDAO代碼:
@Component public class BaseDAO { public String service() { return "Success!"; } }
Services代碼:
//所有業務類的父類 public class BaseService { @Autowired protected BaseDAO baseDAO; } //第一個業務類 @Component public class ServiceA extends BaseService { public String service() { return baseDAO.service(); } } //第二個業務類 @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(); } }
這里根本就不需要進行parent屬性子類的配置,可以完美的提取父類,并且可以順利的使用父類的公用屬性。至于原理,沒有去看源碼的處理方式,估計和上述XML配置是異曲同工的,只是在這里增加了對父類的檢測。
關于“Spring父類變量注入失敗怎么辦”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。