Spring通過父類注入公用屬性的技巧

ganking12發表於2012-06-19

XML配置方式提取父類       

      在使用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>

 

Annotation方式提取父類

上面的方法是在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配置是異曲同工的,只是在這裡增加了對父類的檢測。

相關文章