##注意!!
此篇博文和上一篇博文有一些关联,如已经新建好的各种类的位置,如果对于类的位置不清楚请看上一篇博文
【Spring 4.0】Spring入门之第一个程序HelloWorld实现
##一、关于IOC和DI
**IOC(Inversion of Control)控制反转:**其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
DI(Dependency Injection)依赖注入: IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如: setter 方法)接受来自如容器的资源注入. 相对于 IOC 而言,这种表述更直接。
##二、Bean的配置
###(1)新建一个名为HelloWorld
的JavaBean
(如果按照上一篇博文过来的朋友则不用做Bean的配置了,只需看一下解释就好。因为我是以上一篇的HelloWorld实例来讲解的)
public class HelloWorld {
private String user;
public HelloWorld() {
System.out.println("HelloWorld's constructor...");
}
public void setUser(String user) {
System.out.println("setUser:" + user);
this.user = user;
}
public HelloWorld(String user) {
this.user = user;
}
public void hello(){
System.out.println("Hello: " + user);
}
}
<bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
<!-- 为属性赋值 -->
<property name="user" value="Jerry"></property>
</bean>
####属性解释:
属性 | 属性值 |
---|---|
class | bean 的 指的是HelloWorld的全路径名称,并且由于是通过反射方式创建Bean,因此Bean中必须有无参的构造器。如果没有无参构造器则会出错,当然如果没有显示声明构造器也无妨,因为虚拟机会隐式创建一个无参的构造器。 |
id | 当创建好一个bean之后,如何引用这个bean呢?就需要使用id.它标识bean.并且id唯一。id:Bean 的名称:(1)在 IOC 容器中必须是唯一的。(2)若 id 没有指定,Spring 自动将权限定性类名作为 Bean 的名字。(3)id 可以指定多个名字,名字之间可用逗号、分号、或空格分隔。 |
###(3)在Main.java
中通过容器读出数据
//1. 创建 Spring 的 IOC 容器
//ApplicationContext:代表IOC容器
//ClassPathXmlApplicationContext:是ApplicationContext接口的实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 从 IOC 容器中获取 bean 的实例
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
//根据类型来获取 bean 的实例: 要求在 IOC 容器中只有一个与之类型匹配的 bean, 若有多个则会抛出异常.
//一般情况下, 该方法可用, 因为一般情况下, 在一个 IOC 容器中一个类型对应的 bean 也只有一个.
// HelloWorld helloWorld1 = ctx.getBean(HelloWorld.class);
//3. 使用 bean
helloWorld.hello();
####注意!
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用。
###三、属性注入方式
在Spring中,致辞三种依赖注入的方式
####(1)属性注入
<!-- 配置一个 bean -->
<bean id="helloWorld2" class="com.spring.helloworld.HelloWorld">
<!-- 为属性赋值 -->
<!-- 通过属性注入: 通过 setter 方法注入属性值 -->
<property name="user" value="Tom"></property>
</bean>
- 属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
- 属性注入使用
<property>
元素, 使用name
属性指定 Bean 的属性名称,value
属性或 子节点指定属性值 - 属性注入是实际应用中最常用的注入方式
####(2)构造器注入
#####演示:
######1.添加Car类
public class Car {
private String company;
private String brand;
private int maxSpeed;
private float price;
public Car(String company, String brand, float price) {
super();
this.company = company;
this.brand = brand;
this.price = price;
}
public Car(String company, String brand, int maxSpeed) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public Car(String company, String brand, int maxSpeed, float price) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
this.price = price;
}
@Override
public String toString() {
return "Car [company=" + company + ", brand=" + brand + ", maxSpeed="
+ maxSpeed + ", price=" + price + "]";
}
}
######2.配置bean:
<!-- 若一个 bean 有多个构造器, 如何通过构造器来为 bean 的属性赋值? -->
<!-- 可以根据 index 和 value 进行更加精确的定位. -->
<bean id="car" class="com.spring.helloworld.Car">
<constructor-arg value="KUGA" ></constructor-arg>
<constructor-arg value="ChangAnFord" ></constructor-arg>
<constructor-arg value="250000" ></constructor-arg>
</bean>
######3.主方法调用:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car) ctx.getBean("car");
System.out.println(car);
######4.结果
#####注意!
上面的构造器只是为了其中的前三个属性进行初始化,bean中的配置其实是按照顺序来初始化的,当然如果构造器非常多,如何对bean进行配置呢?
public Car(String company, String brand, float price) {
super();
this.company = company;
this.brand = brand;
this.price = price;
}
public Car(String company, String brand, int maxSpeed) {
super();
this.company = company;
this.brand = brand;
this.maxSpeed = maxSpeed;
}
<bean id="car" class="com.spring.helloworld.Car">
<constructor-arg value="KUGA" index="1"></constructor-arg>
<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
<bean id="car3" class="com.spring.helloworld.Car">
<constructor-arg value="BAOMA" type="java.lang.String"></constructor-arg>
<constructor-arg value="ChangAnFord" type="java.lang.String"></constructor-arg>
<constructor-arg value="250000" type="int"></constructor-arg>
</bean>
- (1)可以创建
index
:<constructor-arg value="audi" index="0"></constructor-arg>
- (2)构造函数也是重载的,区分重载的是参数个数和类型,个数不同好办,相同的时候就可以在后面注明类型。
<constructor-arg value="BAOMA" type="java.lang.String"></constructor-arg>
**(使用
type
来注明类型) **
结果:
###四、注入属性值细节
type
来注明类型) **
####(1)特殊字符
字面值:可用字符串表示的值,可以通过<value>
元素标签或 value 属性进行注入。基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。若字面值中包含特殊字符,如有尖括号<>等等,可以使用<![CDATA[]]>
把字面值包裹起来。
<bean id="car2" class="com.spring.helloworld.Car">
<constructor-arg value="ChangAnMazda"></constructor-arg>
<!--
字面值也可以通过 <value> 元素标签
若字面值中包含特殊字符, 则可以使用 DCDATA 来进行赋值. (了解)
-->
<constructor-arg>
<value><![CDATA[<ATARZA>]]></value>
</constructor-arg>
<constructor-arg value="180" type="int"></constructor-arg>
</bean>
####(2)引用其他的Bean
组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能。要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用。在 Bean 的配置文件中, 可以通过<ref>
元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用。也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean。
<!-- 配置 bean -->
<bean id="dao5" class="com.spring.ref.Dao"></bean>
<bean id="service" class="com.spring.ref.Service">
<!-- 通过 ref 属性值指定当前属性指向哪一个 bean! -->
<property name="dao" ref="dao5"></property>
</bean>
####(3)内部Bean
当 Bean 实例仅仅给一个特定的属性使用时, 可以将其声明为内部 Bean. 内部 Bean 声明直接包含在<property>
或 <constructor-arg>
元素里, 不需要设置任何 id 或 name 属性。内部 Bean 不能使用在任何其他地方。
<!-- 声明使用内部 bean -->
<bean id="service2" class="com.spring.ref.Service">
<property name="dao">
<!-- 内部 bean, 类似于匿名内部类对象. 不能被外部的 bean 来引用, 也没有必要设置 id 属性 -->
<bean class="com.spring.ref.Dao">
<property name="dataSource" value="c3p0"></property>
</bean>
</property>
</bean>
####(4)Null值
可以使用专用的<null/>
元素标签为 Bean 的字符串或其它对象类型的属性注入 null 值。
<bean id="dao2" class="com.spring.ref.Dao">
<!-- 为 Dao 的 dataSource 属性赋值为 null, 若某一个 bean
的属性值不是 null, 使用时需要为其设置为 null(了解) -->
<property name="dataSource"><null/></property>
</bean>
####(5)级联属性
和 Struts、Hiberante 等框架一样,Spring 支持级联属性的配置。
<bean id="action" class="com.spring.ref.Action">
<property name="service" ref="service2"></property>
<!-- 设置级联属性 -->
<property name="service.dao.dataSource" value="DBCP2"></property>
</bean>
####(6)集合属性
在 Spring中可以通过一组内置的 xml 标签(例如: <list>
, <set>
或 <map>
) 来配置集合属性
#####1.配置java.util.List
类型的属性
需要指定<list>
标签, 在标签里包含一些元素. 这些标签可以通过 <value>
指定简单的常量值, 通过<ref>
指定对其他 Bean 的引用. 通过<bean>
指定内置 Bean 定义. 通过<null/>
指定空元素. 甚至可以内嵌其他集合。
<!-- 装配集合属性 -->
<bean id="user" class="com.spring.helloworld.User">
<property name="userName" value="Jack"></property>
<property name="cars">
<!-- 使用 list 元素来装配集合属性 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
</bean>
######注意!
数组的定义和 List 一样, 都使用 <list>
#####2.配置java.util.Set
类型的属性
java.util.Map
通过 <map>
标签定义, <map>
标签里可以使用多个 <entry>
作为子标签. 每个条目包含一个键和一个值。
<bean id="user7" class="com.spring.helloworld.User">
<property name="userName" value="Rose"></property>
<property name="wifeName" value="JACK"></property>
<!-- 使用 Map 元素来装配集合属性 -->
<property name="carmap">
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car"></entry>
</map>
</property>
</bean>
######注意!
- 必须在
<key>
标签里定义键 - 因为键和值的类型没有限制, 所以可以自由地为它们指定
<value>
,<ref>
,<bean>
或<null>
元素。 - 可以将 Map 的键和值作为
<entry>
的属性定义: 简单常量使用key
和value
来定义; Bean 引用通过key-ref
和value-ref
属性定义。
#####3.配置java.util.Properties
类型的属性
使用 <props>
定义java.util.Properties
, 该标签使用多个 <prop>
作为子标签. 每个<prop>
标签必须定义key
属性.实际应用于配置数据库连接池。
######第一步:新建DataSource类
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "DataSoure [properties=" + properties +"]" ;
}
}
######第二步:配置bean
<bean id="dataSource" class="com.spring.helloworld.DataSource">
<property name="properties" >
<props>
<prop key="user">rout</prop>
<prop key="password">rout</prop>
<prop key="jdbcUrl">jdbc:mysql://localhost/hibernate</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
######第三步:打印相关信息
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
######第四步:结果
DataSoure[properties={driverClass=com.mysql.jdbc.Driver, user=rout, password=rout, jdbcUrl=jdbc:mysql://localhost/hibernate}]
#####4.使用 utility scheme
定义集合
使用基本的集合标签定义集合时, 不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合.。可以使用 util schema 里的集合标签定义独立的集合 Bean. 需要注意的是, 必须在<beans>
根元素里添加 util schema 定义。
######第一步:导入util命名空间
打开applicationContext
如图按顺序设置
######第二步:使用util:list
声明集合类型的 bean
<!-- 声明集合类型的 bean -->
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
<bean id="user2" class="com.spring.helloworld.User">
<property name="userName" value="Rose"></property>
<!-- 引用外部声明的 list -->
<property name="cars" ref="cars"></property>
</bean>
#####5.使用 p 命名空间
为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过<bean>
元素属性的方式配置 Bean 的属性。使用 p 命名空间后,基于 XML 的配置方式将进一步简化。
<!-- 通过p命名空间为bean的属性赋值,需要导入p命名空间 -->
<bean id="user3" class="com.spring.helloworld.User"
p:cars-ref="cars" p:userName="Titannic"></bean>