Spring中bean的继承与抽象代码示例
我们在应用spring时,在一般的设计时,肯定要用的抽象类。那在spring中怎么样配置这些抽象bean呢。请看下面:
如果两个bean 之间的配置信息非常相似,可利用继承来减少重复配置工作。
继承是指子bean 定义可从父bean 定义继承部分配置信息,也可覆盖特定的配置信息,或者添加一些配置。使用继承配置可以节省很多的配置工作。在实际应用中,通用配置会被配置成模板,可供子bean 继承。
使用abstract 属性
正如前面所介绍的,通用的配置会被配置成模板,而模板不需要实例化,仅仅作为子bean 定义的模板使用。而applicationcontext 默认预初始化所有的singleton bean 。使用abstract 属性,可以阻止模板bean 被预初始化。abstract 属性为true 的bean 称为抽象bean ,容器会忽略所有的抽象bean 定义,预初始化时不初始化抽象bean。如果没有定义abstract 属性,该属性默认为false 。如下配置文件定义了一个抽象bean ,该抽象bean 作为模板使用:
public class steelaxe implements axe { //count 是个状态值,每次执行chop 方法该值增加1 private int count = 0; public steelaxe(){ system.out.println("spring实例化依赖bean: steelaxe 实例.. ."); } //测试用方法 public string chop(){ return "钢斧砍柴真快" + ++count; } } public class chinese implements person //面向axe 接口编程,而不是具体的实现类 private axe axe; //默认的构造器 public chinese(){ system.out.println("spring实例化主调bean: chinese 实例... "); } //设值注入所需的setter 方法 public void setaxe( axe axe){ system.out.pr工ntln (" spring 执行依赖关系注入..."); this.axe = axe; } //实现person 接口的useaxe 方法 public void useaxe(){ system.out.println(axe.chop()); } }
<?xml version="1.0" encoding="gb2312"?> <!一指定spring 配置文件的dtd> <ldoctype beans publ工c "-//spring//dtd bean//en" ''http://www.springframework.org/dtd/spring-beans.dtd''> <!一spring 配置文件的根元素一〉 <beans> <bean id="steelaxe" class="lee.steelaxe"/> <!… 通过abstract 属性定义该bean 是抽象bean--> <bean id="chinesetemplate" class="lee.chinese" abstract="true"> <!一定义依赖注入的属性一〉 <property name="axe"> <ref local="steelaxe"/> </property> </bean> </beans>
从配置文件中可以看出,抽象bean 的定义与普通bean 的定义几乎没有区别,仅仅增加abstract 属性为true ,但主程序执行结果却有显著的差别。下面的主程序采用appliactioncontext 作为spring 容器, appliationcontext 默认预初始化所有的singleton bean。其主程序部分如下:
public class beantest { public static void main(string[] args)throws exception{ applicationcontext ctx = new filesysternxmlapplicationcontext("bean.xml"); } } //主程序部分仅仅实例化了applicationcontext,在实例化applicationcontext时,默认实例化singleton bean。
程序执行结果如下:
spring 实例化依赖bean: steelaxe 实例.. .
容器并没有实例化chinesetemplate bean ,而忽略了所有声明为abstract 的beano 如果取消abstract 属性定义,则程序执行结果如下:
spring 实例化依赖bean: steelaxe 实~j...
spring 实例化主调bean: chinese 实例.. .
spring 执行依赖关系注入...
可以看出,抽象bean 是一个bean 模板,容器会忽略抽象bean 定义,因而不会实例化抽象bean。但抽象bean 无须实例化,因此可以没有class 属性。如下的配置文件也有效:
<?xml version="1.0" e口coding="gb2312"?> <!一指定spring 配置文件的dtd> <!doctype beans public "-/!spring//dtd bean//en" "http://www.springframework.org/dtd/spring-beans.dtd''> <! -- spring 配置文件的根元素--> <beans> <bean id="steelaxe" class="lee.steelaxe"/> <!一通过abstract 属性定义该bean 是抽象bean,抽象bean 没有指定class 属性一〉 <bean id="chinesetemplate" abstract="true"> <!… 定义依赖注入的属性一〉 <property name="axe"> <ref local="steelaxe"/> </property> </bean〉 </beans>
注意:抽象bean 不能实例化,既不能通过getbean 获得抽象bean,也不能让其他bean 的ref 属性值指向抽象bean,因而只要企图实例化抽象bean,都将导致错误。
定义子bean
我们把指定了parent 属性值的bean 称为子bean; parent 指向子bean 的模板,称为父bean 。子bean 可以从父bean 继承实现类、构造器参数及属性值,也可以增加新的值。如果指定了init-method , destroy-method 和factory-method 的属性,则它们会覆盖父bean的定义。子bean 无法从父bean 继承如下属性: depends-on, autowire, dependency-check,singleton, lazy-init。这些属性将从子bean 定义中获得,或采用默认值。通过设置parent 属性来定义子bean , parent 属性值为父bean id。修改上面的配置文件如下,增加了子bean 定义:
<?xml version="1.0" encoding="gb2312"?> <!一指定spring 配置文件的dtd> <ldoctype beans publ工c "-//spring//dtd bean//en" ''http://www.springframework.org/dtd/spring-beans.dtd''> <!-- spring 配置文件的根元素一〉 <beans> <bean id="steelaxe" class="lee.steelaxe"/> <!一通过abstract 属性定义该bean 是抽象bean--> <bean id="chinesetemplate" class="lee.chinese" abstract="true"> <!-- 定义依赖注入的属性一〉 <property name="axe"> <ref local="steelaxe"/> </property> </bean> <!一通过parent 属性定义子bean ? <bean id="chinese" parent="chinesetemplate"/> </beans>
子bean 与普通bean 的定义并没有太大区别,仅仅增加了parent 属性。子bean 可以没有class 属性,若父bean 定义中有class 属性,则子bean 定义中可省略其class 属性,但子bean 将采用与父bean 相同的实现类。
测试程序修改如下:
public class beantest { public static void main(string[] args)throws exception{ applicationcontext ctx = new filesysternxmlapplicationcontext("bean.xml"); person p = (person)ctx.getbean("chinese"); p.useaxe(); } }
程序执行结果如下:
spring 实例化依赖bean: stee1axe 实例.. .
spring实例化主调bean: chinese 实例.. .
spring 执行依赖关系注入...
钢斧砍柴真快
另外,子bean 从父bean 定义继承了实现类并依赖bean 。但子bean 也可覆盖父bean的定义,看如下的配置文件:
//axe 的实现类stoneaxe如下: public class stoneaxe implements axe //默认构造器 public stoneaxe(){ system.out.println("spring实例化依赖bean: stoneaxe实例.. ."); } //实现axe 接口的chop 方法 public string chop(){ return "石斧砍柴好慢"; } }
chinese子类如下:
public class shanghai extends chinese { public void show() { system.out.println("子bean ,中国的上海"); } }
<?xm1 version="1.0" encoding="gb2312"?> <! 指定spring 配置文件的dtd> <ldoctype beans public "-//spring//dtd bean//en" ''http://www.springframework.org/dtd/spring-beans.dtd''> <! -- spring 配置文件的根元素一〉 <beans> <bean id="steelaxe" class="lee.steelaxe"/> <bean id="stoneaxe" class="lee.stoneaxe"/> <!一通过abstract 属性定义该bean 是抽象bean--> <bean id="chinesetemplate" class="lee.chinese" abstract="true"> <property name="axe"> <ref local="steelaxe"/> </property> </bean> <!一通过parent 属性定义子bean--> <bean id="shanghai" parent="chinesetemplate"> <!一覆盖父bean 的依赖定义…〉 <property name="axe"> <ref local="stoneaxe"/> </property> </bean> </beans>
此时,子bean 的依赖不再是父bean 定义的依赖了。注意,这个时候的父类lee.chinese 不能是抽象类,(说明下:有abstract="true")不一定说明这个类一定是个抽象类,不是抽象类同样可以在spring里定义为抽象bean,如果你的class是抽象类,那这个时候就不能用父bean的class,一定要在子bean中定义class来初始化这个子bean)
测试程序修改如下:
public class beantest { public static void main(string[] args)throws exception{ applicationcontext ctx = new filesysternxmlapplicationcontext("bean.xml"); person p = (person)ctx.getbean("shanghai"); p.useaxe(); } }
按上面的测试程序执行结果如下:
spring 实例化依赖bean: steelaxe 实例.. .
spring 实例化依赖bean: stoneaxe 实例.. .
spring 实例化主调bean: chinese 实例.. .
spring 执行依赖关系注入...
石斧砍柴好慢
注意:上例中的子bean 定义都没有class 属性,因为父bean 定义中已有class 属性,子bean 的class 属性可从父bean 定义中继承,但需要注意的是从父bean继承class时,父bean一定不能是抽象类,因为抽象类不能创建实例;如果父bean 定义中也没有指定class 属性,则子bean 定义中必须指定class 属性,否则会出错;如果父bean 定义指定了class 属性,子bean 定义也指定了class 属性,则子bean 将定义的class 属性覆盖父bean 定义的class属性。
spring 中bean的继承和java中的继承截然不同,前者是实例与实例之间的参数的延续,后者是一般到特殊的细化,前者是对象和对象之间的关系,后者是类和类之间的关系。
a.spring中的子bean和父bean可以是不同的类型,但是java中的继承,子类是一种特殊的父类;
b.spring中的bean的继承是实例之间的关系,主要表现在参数的延续,而java中的继承是类与类之间的关系,主要体现在方法和属性的延续。
c.spring中子bean不可以作为父bean使用,不具备多态性,java中的子类实例完全可以当作父类实例使用。
总结
本文有关spring中bean的继承与抽象代码示例的内容就到这里,希望对大家有所帮助。有兴趣的朋友可以参阅本站其他专题,精彩不断。感谢大家对本站的支持!