spring05----DI的配置使用
Posted Hermioner
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring05----DI的配置使用相关的知识,希望对你有一定的参考价值。
一. 依赖和依赖注入的基本概念
1. 类之间的关系
传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系:
泛化:表示类与类之间的继承关系、接口与接口之间的继承关系;
实现:表示类对接口的实现;
依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识 关系”,只在某个特定地方(比如某个方法体内)才有关系。
关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示;
聚合:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是 一种弱关联;
组合:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周 期,是一种强关联;
Spring IoC容器的依赖有两层含义:Bean依赖容器和容器注入Bean的依赖资源:
Bean依赖容器:也就是说Bean要依赖于容器,这里的依赖是指容器负责创建Bean并管理Bean的生命周期,正是由 于由容器来控制创建Bean并注入依赖,也就是控制权被反转了,这也正是IoC名字的由来,此处的有依赖是指Bean和 容器之间的依赖关系。
容器注入Bean的依赖资源:容器负责注入Bean的依赖资源,依赖资源可以是Bean、外部文件、常量数据等,在 Java中都反映为对象,并且由容器负责组装Bean之间的依赖关系,此处的依赖是指Bean之间的依赖关系,可以认为是 传统类与类之间的“关联”、“聚合”、“组合”关系。
2. 为什么要引入DI?
动态替换Bean依赖对象,程序更灵活:替换Bean依赖对象,无需修改源文件:应用依赖注入后,由于可以采用配置 文件方式实现,从而能随时动态的替换Bean的依赖对象,无需修改java源文件;
更好实践面向接口编程,代码更清晰:在Bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容 器注入依赖实现;
更好实践优先使用对象组合,而不是类继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实践对象组合
- 采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖
Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;
- 而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继
承导致Bean与子Bean之间高度耦合,难以复用。
增加Bean可复用性:依赖于对象组合,Bean更可复用且复用更简单;
降低Bean之间耦合:由于我们完全采用面向接口编程,在代码中没有直接引用Bean依赖实现,全部引用接口,而且 不会出现显示的创建依赖对象代码,而且这些依赖是由容器来注入,很容易替换依赖实现类,从而降低Bean与依赖之间 耦合;
代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码 结构更清晰。
二. 依赖注入的方式
1. 构造器注入
构造器注入可以根据参数索引注入、参数类型注入或Spring3支持的参数名注入(但参数名注入是有限制的,个人觉得好麻烦啊,因此只介绍前两种)
(1)根据参数索引注入
使用标签“<constructor-arg index="1" value="1"/>"来指定注入的依赖,其中index表示索引,从0开始,即第一个参数索引为0,value来指定注入的常量值,配置方式如下:
<constructor-arg index="0" value="Hello World!"/>
(2)根据参数类型注入
使用标签“ <constructor-arg type="java.lang.String" value="Hello World!"/>” 来指定注入的依赖,其中“type”表示需要匹配的参数类型,可以是基本类型也可以是其它类型,如“int”、“java.lang.String”、“value”来指定注入的常量值,配置方式如下:
(3)举例:
<!-- 通过构造器参数索引方式依赖注入 --> <bean id="byIndex" class="com.test.spring.HelloImpl2"> <constructor-arg index="0" value="Hello World"></constructor-arg> <constructor-arg index="1" value="2"></constructor-arg> </bean> <!-- 通过构造器参数类型方式依赖注入 --> <bean id="byName" class="com.test.spring.HelloImpl2"> <constructor-arg type="java.lang.String" value="Hello Spring"></constructor-arg> <constructor-arg type="int" value="3"></constructor-arg> </bean>
1 public class HelloImpl2 implements HelloApi{ 2 private String message; 3 private int a; 4 public HelloImpl2(String message,int a) { 5 this.message=message; 6 this.a=a; 7 } 8 public void sayHello() { 9 System.out.println(message+": "+a); 10 } 11 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("byIndex"); 5 aHelloImpl2.sayHello(); 6 7 HelloImpl2 bHelloImpl2=(HelloImpl2) context.getBean("byName"); 8 bHelloImpl2.sayHello(); 9 } 10 11 } 12 13 Hello World: 2 14 Hello Spring: 3
2. 静态工厂注入
<bean id="bystaticFactory" class="com.test.spring.HelloApiStaticFactory" factory-method="newInstance"> <constructor-arg index="0" value="haha"></constructor-arg> <constructor-arg index="1" value="3"></constructor-arg> </bean>
1 public class HelloApiStaticFactory { 2 //工厂方法 3 public static HelloApi newInstance(String message,int a) { 4 //返回需要的Bean实例 5 return new HelloImpl2(message,a); 6 } 7 8 } 9 10 11 public class HelloImpl2 implements HelloApi{ 12 private String message; 13 private int a; 14 public HelloImpl2(String message,int a) { 15 this.message=message; 16 this.a=a; 17 } 18 public void sayHello() { 19 System.out.println(message+": "+a); 20 } 21 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("bystaticFactory"); 5 aHelloImpl2.sayHello(); 6 7 } 8 9 } 10 11 12 haha: 3
3. 实例工厂类
<bean id="byinstanceFactory" factory-bean="instanceFactory" factory-method="newInstance"> <constructor-arg index="0" value="haha"></constructor-arg> <constructor-arg index="1" value="3"></constructor-arg> </bean> <bean id="instanceFactory" class="com.test.spring.HelloApiInstanceFactory"></bean>
1 public class HelloApiInstanceFactory { 2 public HelloApi newInstance(String message,int a) { 3 return new HelloImpl2(message,a); 4 } 5 6 } 7 8 public class HelloImpl2 implements HelloApi{ 9 private String message; 10 private int a; 11 public HelloImpl2(String message,int a) { 12 this.message=message; 13 this.a=a; 14 } 15 public void sayHello() { 16 System.out.println(message+": "+a); 17 } 18 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("byinstanceFactory"); 5 aHelloImpl2.sayHello(); 6 7 } 8 9 } 10 11 haha: 3
4. setter注入
setter注入,是通过在通过构造器、静态工厂或实例工厂实例好Bean后,通过调用Bean类的setter方法进行注入依赖。setter注入方式只有一种根据setter名字进行注入。如下:
<bean id="bySetter" class="com.test.spring.HelloImpl2">
<property name="message" value="Hello World!"></property>
<property name="a" value="3"></property>
</bean>
1 public class HelloImpl2 implements HelloApi{ 2 private String message; 3 private int a; 4 public void setMessage(String message) { 5 this.message = message; 6 } 7 public void setA(int a) { 8 this.a = a; 9 } 10 public void sayHello() { 11 System.out.println(message+": "+a); 12 } 13 14 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("bySetter"); 5 aHelloImpl2.sayHello(); 6 7 } 8 9 } 10 11 12 Hello World!: 3
note: setter注入的方法名要遵循“ JavaBean getter/setter 方法名约定”:
JavaBean:是本质就是一个POJO类,但具有一下限制: 该类必须要有公共的无参构造器,如public HelloImpl4() {}; 属性为private访问级别,不建议public,如private String message; 属性必要时通过一组setter(修改器)和getter(访问器)方法来访问; setter方法,以“set” 开头,后跟首字母大写的属性名,如“setMesssage”,简单属性一般只有一个方法参 数,方法返回值通常为“void”; getter方法,一般属性以“get”开头,对于boolean类型一般以“is”开头,后跟首字母大写的属性名,如 “getMesssage”,“isOk”;
还有一些其他特殊情况,比如属性有连续两个大写字母开头,如“URL”,则setter/getter方法为:“setURL” 和“getURL”,其他一些特殊情况请参看“Java Bean”命名规范。
5. 注入常量
注入常量是依赖注入中最简单的。配置方式如下所示:
<property name="message" value="Hello World!"/>
注意此处“value”中指定的全是字符串,由Spring容器将此字符串转换成属性所需要的类型,如果转换出错,将抛出相应的异常。
Spring容器目前能对各种基本类型把配置的String参数转换为需要的类型。
注:Spring类型转换系统对于boolean类型进行了容错处理,除了可以使用“true/false”标准的Java值进行注入,还 能使用“yes/no”、“on/off”、“1/0”来代表“真/假”,所以大家在学习或工作中遇到这种类似问题不要觉得是人 家配置错了,而是Spring容错做的非常好。
6. 注入Bean ID(???)
7. 注入集合类型
包括Collection类型、Set类型、List类型
(1)List类型:需要使用<List>标签来配置注入,具体配置如下:
- 可选的“value-type”属性,表示列表中条目的数据的类型,默认是String类型。
- 也可以采用发行来代替具体的类型,比如 value-type="java.util.List<String>"
<bean id="listBean" class="com.test.spring.ListBean"> <property name="values"> <list value-type="int"> <value>1</value> <value>2</value> <value>3</value> </list> </property> </bean>
1 public class ListBean { 2 private List values; 3 4 public List getValues() { 5 return values; 6 } 7 8 public void setValues(List values) { 9 this.values = values; 10 } 11 12 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 ListBean listBean=(ListBean) context.getBean("listBean"); 5 System.out.println(listBean.getValues().get(1)); 6 System.out.println(listBean.getValues().get(1).getClass()); 7 } 8 9 } 10 11 12 2 13 class java.lang.Integer
(2)set类型:需要使用<set>标签来配置注入。其配置参数和<list>完全一样。
8. 注入数组类型
需要使用<array>标签来配置注入,其中标签属性“value-type”和“merge”和<list>标签含义 完全一样,具体配置如下:
<bean id="arrayBean" class="com.test.spring.ArrayBean">
<property name="array">
<array value-type="int">
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
</bean>
1 public class ArrayBean { 2 private int array[]; 3 4 public int[] getArray() { 5 return array; 6 } 7 8 public void setArray(int[] array) { 9 this.array = array; 10 } 11 12 13 } 14 15 16 public class HelloTest { 17 public static void main(String args[]) { 18 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 19 ArrayBean arrayBean=(ArrayBean) context.getBean("arrayBean"); 20 System.out.println(arrayBean.getArray()[1]); 21 22 } 23 24 } 25 26 27 2
note:也可以注入二维数组:
9. 注入字典(Map)类型
需要使用<map>标签来配置注入,,其属性 “key-type”和“value-type”分别指定“键”和“值”的数据类型,其含义和<list>标签的“value-type”含义一 样,在此就不罗嗦了,并使用<key>子标签来指定键数据,<value>子标签来指定键对应的值数据,具体配置如下
<bean id="mapBean" class="com.test.spring.MapBean"> <property name="values"> <map key-type="java.lang.String" value-type="java.lang.Integer"> <entry key="hello" value="23"></entry> </map> </property> </bean>
1 public class MapBean { 2 private Map<String, Integer> values; 3 4 public Map<String, Integer> getValues() { 5 return values; 6 } 7 8 public void setValues(Map<String, Integer> values) { 9 this.values = values; 10 } 11 12 13 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 MapBean mapBean=(MapBean) context.getBean("mapBean"); 5 System.out.println(mapBean.getValues().get("hello")); 6 } 7 8 } 9 10 23
10. Properties注入
Spring能注入java.util.Properties类型数据,需要使用<props>标签来配置注入,键和值类型必 须是String,不能变,子标签<prop key=”键”>值</prop>来指定键值对,具体配置如下
<bean id="propertiesBean" class="com.test.spring.PropertiesBean">
<property name="values">
<props value-type="int" merge="default"> <!-- 虽然指定了value-type,但实际上该属性不起作用,因为Properties的key和value必须都是String类型 -->
<prop key="1">a</prop>
<prop key="2">b</prop>
</props>
</property>
</bean>
1 public class PropertiesBean { 2 private Properties values; 3 4 public Properties getValues() { 5 return values; 6 } 7 8 public void setValues(Properties values) { 9 this.values = values; 10 } 11 12 13 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 PropertiesBean propertiesBean=(PropertiesBean) context.getBean("propertiesBean"); 5 System.out.println(propertiesBean.getValues()); 6 } 7 8 } 9 10 {2=b, 1=a}
11. 注入Bean之间的关系(注入依赖Bean)
可以有两种方式,一种是通过构造函数,另外一种是通过setter方式来注入依赖的Bean
“<constructor-arg index="0" value="Hello World!"/>”和“<property name="message" value="Hello World!"/>”中的value属性替换成bean属性,其中bean属性指定配置文件中的其 他Bean的id或别名。另一种是把<value>标签替换为<.ref bean=”beanName”>
(1)构造参数方式注入依赖的Bean
<ref="beanName">----只可以是这种
<bean id="di" class="com.test.spring.HelloImpl2"> </bean> <!-- 通过过构造器注入 --> <bean id="bean1" class="com.test.spring.HelloApiDecorator"> <constructor-arg index="0" ref="di"/> </bean>
(2)setter方式注入依赖的Bean
<.ref bean=”beanName”>---只可以是这种
<!-- 通过构造器注入 -->
<bean id="bean2" class="com.test.spring.HelloApiDecorator">
<property name="helloApi">
<ref bean="di"/>
</property>
</bean>
(3)举例
<!-- 定义依赖Bean --> <bean id="di" class="com.test.spring.HelloImpl2"> </bean> <!-- 通过过构造器注入 --> <bean id="bean1" class="com.test.spring.HelloApiDecorator"> <constructor-arg index="0" ref="di"/> </bean> <!-- 通过构造器注入 --> <bean id="bean2" class="com.test.spring.HelloApiDecorator"> <property name="helloApi"> <ref bean="di"/> </property> </bean>
1 public interface HelloApi { 2 public void sayHello(); 3 4 } 5 6 7 public class HelloImpl2 implements HelloApi{ 8 public void sayHello() { 9 System.out.println("hello"); 10 } 11 12 } 13 14 15 public class HelloApiDecorator implements HelloApi{ 16 private HelloApi helloApi; 17 public HelloApiDecorator() { 18 19 } 20 public HelloApiDecorator(HelloApi helloApi) { 21 this.helloApi=helloApi; 22 } 23 public void sayHello() { 24 System.out.println("before decorator"); 25 helloApi.sayHello(); 26 System.out.println("after decorator"); 27 } 28 public void setHelloApi(HelloApi helloApi) { 29 this.helloApi = helloApi; 30 } 31 32 33 }
1 public class HelloTest { 2 public static void main(String args[]) { 3 ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); 4 //通过构造器方式注入 5 HelloApi helloApi=(HelloApi) context.getBean("bean1"); 6 helloApi.sayHello(); 7 //通过setter方法注入 8 HelloApi helloApi2=(HelloApi) context.getBean("bean2"); 9 helloApi2.sayHello(); 10 } 11 12 } 13 14 15 before decorator 16 hello 17 after decorator 18 before decorator 19 hello 20 after decorator
12. 内部定义Bean
内部Bean就是在<property>或<constructor-arg>内通过<bean>标签定义的Bean,该Bean不管是否指定id或 name,该Bean都会有唯一的匿名标识符,而且不能指定别名,该内部Bean对其他外部Bean不可见,具体配置如下
<bean id="bean1" class="com.test.spring.HelloApiDecorator"> <property name="helloApi"> <bean id="bean2" class="com.test.spring.HelloImpl2"/> </property> </bean>
1 public class HelloApiDecorator implements HelloApi{ 2 private HelloApi helloApi; 3 public HelloApiDecorator() { 4 5 } 6 public HelloApiDecorator(HelloApi helloApi) { 7 this.helloApi=helloApi; 8 } Spring MVC 3.2 Thymeleaf Ajax 片段spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段
Spring boot:thymeleaf 没有正确渲染片段