Spring的配置形式有两种:基于XML配置和基于注解配置。

  Bean的配置方式有以下几种:


    1. 通过全类名,即通过反射的方式;

    2. 通过工厂方法,有静态工厂方法和实例工厂方法;

    3. 通过FactoryBean配置;



通过XML文件配置bean

本篇文章将按照下面的目录来说明基于XML的方式配置bean

  1. JavaBean的创建

  2. 通过XML配置的方式来配置bean

    1. 属性注入

    2. 构造器注入

    3. 工厂方法注入(很少使用)

    1. XMLbean的配置;

    2. spring的依赖注入的方式

  3. 测试方法 

    1. 通过id

    2. 通过类型

    3. ApplicationContext的简单说明;

    1. IoC容器的实例化;

    2. bean的获取方法

  使用XML配置bean,需要通过bean标签完成,通过bean标签的class属性来指定全类名,id属性指定一个唯一标识,这个标识需要在IoC容器中是唯一的。如果不指定的话,spring将会自动的将权限定性类名作为id。实际上这种方式已经在第一篇文章《Spring学习系列之——第一章:Spring版本的HelloWorld》中使用了,下面对这种方式进行一个简单的总结。


1、JavaBean的创建

  首先创建一个JavaBean,重写toString()方法是为了方便测试看结果,这个JavaBean什么都没有,只有一个属性和对应的getter和setter方法,我们都知道,在不定义构造方法的时候,会自动生成一个无参的构造方法。

package com.spring.blog.helloworld;

public class HelloSpring {
	private String str;

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	@Override
	public String toString() {
		return "HelloSpring [str=" + str + "]";
	}
	
}


2、通过XML配置的方式来配置Bean


a、通过XML配置的方式配置bean

  接下来看一下怎么配置这个bean,下面是applicationContext.xml中的内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- 配置Springbean -->
	<bean id="helloSpring" class="com.spring.blog.helloworld.HelloSpring">
		<property name="str" value="Spring is good!"></property>
	</bean>
</beans>

  这种配置方式,有以下几个特点:


    1. 通过bean标签配置;

    2. class属性制定bean的全类名,通过反射的方式在IoCr容器中创建bean,被指定的类需要有一个无参的构造方法。大家可以尝试着给HelloSpring类只提供一个带参数的构造,并进行测试。

    3. id是bean在IoC容器中的标识,需要是唯一的。

b、spring依赖注入的方式

    属性注入:最常用的注入方式

  上面的配置方式就是属性注入方式,需要注意的是:name是和setter方法保持一致的!什么意思,请看下面的代码:

//str属性不变
private String str;
//setStr改为setStr2
public void setStr2(String str) {
	this.str = str;
}

相对于的xml配置文件中bean的定义应该如下:name是str2,而不是str

<!-- 配置Springbean -->
<bean id="helloSpring" class="com.spring.blog.helloworld.HelloSpring">
	<property name="str2" value="Spring is good!"></property>
</bean>

    构造方法注入

新建JavaBean,Car类,定义了两个构造方法:

package com.study.spring;

public class Car {
	private String brand;
	private String corp;
	private double price;
	private int maxSpeed;

	public Car(String brand, String corp, double price) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.price = price;
	}
	public Car(String brand, String corp, int maxSpeed) {
		super();
		this.brand = brand;
		this.corp = corp;
		this.maxSpeed = maxSpeed;
	}

}

下面看一下XML文件的配置方式:

<!-- 通过构造方法配置Bean 通过构造器注入属性值可以指定参数的位置(index指定)和参数的类型(type指定)已区分构造器 -->
<!--  使用第二个构造方法 -->
<bean id="car" class="com.study.spring.Car">
	<constructor-arg value="Audi" index="0"></constructor-arg>
	<constructor-arg value="Shanghai" index="1"></constructor-arg>
	<constructor-arg value="3000" index="2" type="double"></constructor-arg>
</bean>
<!--  使用第二个构造方法  -->
<bean id="car2" class="com.study.spring.Car">
	<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
	<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
	<constructor-arg value="240" type="int"></constructor-arg>
</bean>

通过bean的子标签:constructor-arg注入到对象中区,其中index属性可以指定构造方法中的参数的顺序,type可以指定参数的类型,这样就可以明确要使用的构造器。考虑一下,重载方法:参数个数不同或者参数类型不同,但是名称相同的方法。我认为这里可以这么理解:这里的index属性可以类比为个数,type属性类比为参数类型。


  但是看到上面的配置方式,不知道大家有没有疑问,第一个构造方法三个参数分别是String、String、double类型,第二个构造方法三个参数分别是String、String、int类型的。而我们的配置文件,统统采用的是value="参数值"的形式,但是程序可以运行没有错误,很明显这是spring为我们做了相关的工作,自动的完成了相关的类型转换,像这种可用字符串表示的值,我们称之为字面值。既然是这样的话,不难想象,如果我们不指定type属性,IoC容器在创建bean的时候肯定会使用找到的第一个匹配的构造方法进行创建。下面是去掉type属性之后的运行结果截图,可以看到都把第三个参数赋值给了price:

wKioL1VHbkTTW0laAACI2qzmBCY501.jpg

  对于字面值除了上面的配置方法,可以使用下面的配置方法,即通过使用constructor-arg的子标签value标签进行赋值,对于有特殊符号的,可以使用表达式<![CDATA[]]>把值给包裹起来,例如这里要给第二个参数赋值为<shanghai^>,尖括号(<、>)在XML中是特殊符号

<bean id="car3" class="com.study.spring.Car">
	<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
	<!-- 如果字面包含特殊字符,可以使用 <![CDATA[]]包裹起来 -->
	<!-- 属性值可以使用value子节点进行配置 -->
	<constructor-arg type="java.lang.String">
		<value><![CDATA[<ShangHai^>]]></value>
	</constructor-arg>
	<constructor-arg type="int">
		<value>270</value>
	</constructor-arg>
</bean>


  小结:对于字面值,可以使用字符串表示的值,我们可以通过constructor-arg标签的value属性进行赋值,也可以通过constructor-arg的子标签<value></value>进行赋值,对包含特殊字符的情况可以使用表达式<![CDATA[]]>把值给包裹起来。Java中的基本数据类型及其封装类型(Integer、Long等)和String类型都可以使用上面的字面值的注入方法。


测试方法的解读

 这一部分通过下面两个方面来进行分析:一是IoC容器的实例化;二是如何获取bean?

  接下来看一下测试类:

package com.spring.blog.helloworld;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		//实例化一个IoC容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//从IoC容器中获取bean实例
		HelloSpring helloSpring = (HelloSpring) ctx.getBean("helloSpring");
		//测试获取到的bean实例
		System.out.println(helloSpring);
	}
}


IoC容器的实例化

  说了这么多,一直都在说IoC容器,到底什么是IoC容器?

  Spring 提供了两种类型的IOC容器实现:


    1. BeanFactory,IoC容器基本的实现;

    2. ApplicationContext,提供了更多的高级特性,是BeanFactory的子接口,其实它也是一个 接口。BeanFactory 是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。无论采用哪种方式,配置方式都是一样的

 

  下面我们来看一下ApplicationContext的类图,可以看到它本身是一个接口,下面有很多抽象类都实现了这个接口,它有两个主要的实现类,一个是我们已经使用了的ClassPathXmlApplicationContext,另外一个是FileSystemXmlApplicationContext。

wKioL1VA2fXg8rRHAAKXjTs8P8g533.jpg

 ClassPathXmlApplicationContext:类路径下加载配置文件,可以理解为根目录是src,相对于src目录来写配置文件的位置;

 FileSystemXmlApplicationContext:文件系统中加载配置文件。假如我们的配置文件application-context.xml放在D:/config 目录下面,我们可以通过这个类,传入参数D:\\config\\application-context.xml来初始化IoC容器。

 ConfigurableApplicationContext扩展于ApplicationContext,新增加了两个主要方法:refresh()和close(),让 ApplicationContext具有启动、刷新和关闭上下文的能力。

 ApplicationContext在初始化上下文时就实例化所有单例的Bean。这意味着不管你是否立即使用注册在IoC容器的bean,IoC容器都会创建所有的单例的Bean。关于这一点,我们可以通过提供无参的构造方法,在构造方法中添加输入语句,例如:

//提供无参的构造方法,输出语句是验证用的
public HelloSpring() {
	System.out.println("HelloSpring's constructor...");
}

然后测试类的main方法中只保留下面一句话:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

其实是可以看到下面的输出信息的,说明确实是在初始化IoC容器的时候,实例化了bean:

wKiom1VA3a6RtTO4AAMsnNOtMPE504.jpg


Bean的获取方法 

  1. 通过id获取,即在xml文件中配置bean的时候,设定的id,需要强制类型转换,上面使用的就是这种方法;

  2. 通过类型获取,代码实例如下:

//通过id获取,需要类型转换
HelloSpring helloSpring_1 = (HelloSpring) ctx.getBean("helloSpring");

//通过类型获取,不需要类型转换,缺点是当配置了多个相同类型的bean时,不知道该注入哪一个bean,就会抛出异常
HelloSpring helloSpring =  ctx.getBean(HelloSpring.class);


 暂时先写到这里,关于自动装配,bean之间的继承依赖,bean的作用域等等,后面再写。。。


 上面是自己学习Spring的一些简单的记录和一些个人的理解,如果有不对的地方,希望大家能够给帮忙指正,欢迎大家来讨论。