Spring通过父类注入公用属性的技巧
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" /><bean id="serviceA" ref="baseDAO" /></bean><bean id="serviceB" 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" /><bean id="BaseService" /><property name="baseDAO" ref="baseDAO" /></bean><bean id="serviceA" /><bean id="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" /><bean id="BaseService" /><property name="baseDAO" ref="baseDAO" /></bean><bean id="serviceA" parent="baseService" /><bean id="serviceB" parent="baseService" />
这个时候再运行,就不会报错了。原理是:在Spring的子类Bean配置中,其parent属性作用是指定其父类,并继承父类的注入属性。不仅如此,子类还可以修改或者覆盖父类的属性值。例如上述代码中的子类修改父类的baseDAO到属性:
<bean id="BaseService" /><property name="baseDAO" ref="baseDAO" /></bean><bean id="serviceA" parent="baseService" /><property name="baseDAO" ref="baseDAO2" /></bean>
而对于父类的List等集合属性,子类可以继承父类的值,并且在其基础上进行增加新的值:
<bean id="BaseService" /><property name="listValue"> <list> <value>listValue1</value> <value>listValue2</value> </list> </property> </bean><bean id="serviceA" parent="baseService" /><property name="listValue"> <list> <value>listValue3</value> <value>listValue4</value> </list> </property> </bean>
?
Annotation方式提取父类
上面的方法是在XML配置文件中进行的配置。而对现在Spring3流行的Annotation方式,其实更加的方便,完整示例如下:
BaseDAO代码:
@Componentpublic class BaseDAO {public String service() {return "Success!";}}
Services代码:
//所有业务类的父类public class BaseService {@Autowiredprotected BaseDAO baseDAO;}//第一个业务类@Componentpublic class ServiceA extends BaseService {public String service() {return baseDAO.service();}}//第二个业务类@Componentpublic class ServiceB extends BaseService {public String service() {return baseDAO.service();}}
Action层代码:
@Controller@RequestMapping(value = "/testaction")public class TestAction {@Autowiredprivate ServiceA service;@RequestMapping(value = "/")public @ResponseBody String home(Model model) {return service.service();}}
这里根本就不需要进行parent属性子类的配置,可以完美的提取父类,并且可以顺利的使用父类的公用属性。至于原理,没有去看源码的处理方式,估计和上述XML配置是异曲同工的,只是在这里增加了对父类的检测。