Spring的配置形式有两种:基于XML配置和基于注解配置。
Bean的配置方式有以下几种:
通过全类名,即通过反射的方式;
通过工厂方法,有静态工厂方法和实例工厂方法;
通过FactoryBean配置;
通过XML文件配置bean
本篇文章将按照下面的目录来说明基于XML的方式配置bean
JavaBean的创建
通过XML配置的方式来配置bean
属性注入
构造器注入
工厂方法注入(很少使用)
XMLbean的配置;
spring的依赖注入的方式
测试方法
通过id
通过类型
ApplicationContext的简单说明;
IoC容器的实例化;
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>
这种配置方式,有以下几个特点:
通过bean标签配置;
class属性制定bean的全类名,通过反射的方式在IoCr容器中创建bean,被指定的类需要有一个无参的构造方法。大家可以尝试着给HelloSpring类只提供一个带参数的构造,并进行测试。
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:
对于字面值除了上面的配置方法,可以使用下面的配置方法,即通过使用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容器实现:
BeanFactory,IoC容器基本的实现;
ApplicationContext,提供了更多的高级特性,是BeanFactory的子接口,其实它也是一个 接口。BeanFactory 是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。无论采用哪种方式,配置方式都是一样的
下面我们来看一下ApplicationContext的类图,可以看到它本身是一个接口,下面有很多抽象类都实现了这个接口,它有两个主要的实现类,一个是我们已经使用了的ClassPathXmlApplicationContext,另外一个是FileSystemXmlApplicationContext。
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:
Bean的获取方法
通过id获取,即在xml文件中配置bean的时候,设定的id,需要强制类型转换,上面使用的就是这种方法;
通过类型获取,代码实例如下:
//通过id获取,需要类型转换 HelloSpring helloSpring_1 = (HelloSpring) ctx.getBean("helloSpring"); //通过类型获取,不需要类型转换,缺点是当配置了多个相同类型的bean时,不知道该注入哪一个bean,就会抛出异常 HelloSpring helloSpring = ctx.getBean(HelloSpring.class);
暂时先写到这里,关于自动装配,bean之间的继承依赖,bean的作用域等等,后面再写。。。
上面是自己学习Spring的一些简单的记录和一些个人的理解,如果有不对的地方,希望大家能够给帮忙指正,欢迎大家来讨论。