Spring提供了三种方法进行配置:
- 在XML文件中显式配置
- 在Java的接口和类中实现配置
- 隐式Bean的发现机制和自动装配原则
方式选择的原则:
一)最优先:通过隐式Bean的发现机制和自动装配的原则。
- 好处:减少程序开发者的决定权,简单灵活。
二)其次:Java接口和类中实现配置
- 好处:避免XML配置的泛滥,也更容易。
三)最后:XML方式配置
- 好处:简单易懂
通过XML配置装配Bean
使用XML装配Bean需要定义对应的XML,需要引入对应的XML模式(XSD)文件,这些文件会定义配置Spring Bean的一些元素。

Spring配置文件内容如下:
<?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"> </beans>
然后在beans标签中,添加对应的bean标签来定义Spring Bean。
<!--id:bean唯一标识 class:需要注册到Ioc容器的Bean对象的实现类--> <bean id="account" class="com.company.pojo.Account"> <!-- bean标签注入属性值 1) property标签 name:属性名(setXXX()方法名除去set之后的名称) value:对应属性值 ref:引用已经定义的Bean对象 --> <property name="id" value="3"></property> <property name="name" value="may"></property> <property name="money" value="300"></property> <!-- 2)constructor-arg标签 name:构造方法中参数名称 value:对应的参数值 ref:引用已经定义的Bean对象 --> <constructor-arg name="id" value="3"></constructor-arg> <constructor-arg name="name" value="may"></constructor-arg> <constructor-arg name="money" value="500"></constructor-arg> </bean>
装配集合
public class ComplexCollection { private int id; private List<String> list; private Map<String,String> map; private Properties properties; private Set<String> set; private String[] array; public int getId() { return id; } public void setId(int id) { this.id = id; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } public Set<String> getSet() { return set; } public void setSet(Set<String> set) { this.set = set; } public String[] getArray() { return array; } public void setArray(String[] array) { this.array = array; } }
对应xml配置
<bean id="complexCollection" class="com.company.pojo.ComplexCollection"> <!--装配Integer类型的id--> <property name="id" value="10"></property> <!--装配List类型的list--> <property name="list"> <list> <value>123</value> <value>456</value> <value>789</value> </list> </property> <!--装配Map类型的map--> <property name="map"> <map> <entry key="a" value="123"></entry> <entry key="b" value="456"></entry> <entry key="c" value="789"></entry> </map> </property> <!--装配Properties类型的properties--> <property name="properties"> <props> <prop key="driver">com.microsoft.sqlserver.jdbc.SQLServerDriver</prop> <prop key="url">jdbc:sqlserver://localhost:1433;DatabaseName=testdb</prop> <prop key="username">sa</prop> <prop key="password">123.abc</prop> </props> </property> <!--装配Set类型的set--> <property name="set"> <set> <value>monday</value> <value>tuesday</value> <value>wednesday</value> <value>thursday</value> <value>friday</value> <value>saturday</value> <value>sunday</value> </set> </property> <!--装配String[]类型的array--> <property name="array"> <array> <value>january</value> <value>february</value> <value>march</value> <value>april</value> </array> </property> </bean>
总结:
- List属性为对应的<list>标签进行装配,然后通过多个<value>标签设值。
- Map属性为对应的<map>标签进行装配,然后通过多个<entry>标签设值,只是<entry>包含一个键值对(key-value)的设置。
- Properties属性为对应的<properties>标签进行装配,通过一个<props>标签设值,只是含有多个prop标签,其中有一个必填属性key,然后可以设置值。
- Set属性为对应的<set>标签进行装配,然后通过多个<value>标签设值。
- 对于数组而言,可以使用<array>标签进行装配,然后通过多个<value>标签设值。
对于上述的集合,都可以ref引用已经设置好的Bean对象来设置值。
命名空间装配
除了上述的配置之外,Spring还提供了对应的命名空间的定义,只是在使用命名空间的时候要先引入对应的命名空间和XML模式(XSD)文件。
【c-命名空间】
c-命名空间是在Spring 3.0中引入的,它是在XML中更为简洁地描述构造器参数的方式,要使用它,必须在XML的顶部声明其模式。

注意:是通过构造器参数的方式
Student.java
public class Student { int id; String name; public Student(int id, String name) { this.id = id; this.name = name; } // setter and getter }
在c-命名空间和模式声明之后,就可以使用它来声明构造器参数了。
<!-- 引入 c-命名空间之前 --> <bean name="student1" class="pojo.Student"> <constructor-arg name="id" value="1" /> <constructor-arg name="name" value="学生1"/> </bean> <!-- 引入 c-命名空间之后 --> <bean name="student2" class="pojo.Student" c:id="2" c:name="学生2"/>
c-命名空间属性名已“c:”开头,也就是命名空间的前缀。接下来就是装配的构造器参数名,在此之后如果需要注入对象的话则要跟上-ref(如 c:card-ref="idcard",则对card这个构造器参数注入之前配置名为idcard的bean)。
很显然,使用c-命名空间属性要比使用<constructor-arg>元素精简,并且会直接引用构造器之中参数的名称,有利于使用的安全性。
另外一种替代方式
<bean name="student2" class="pojo.Student" c:_0="3" c:_1="学生3"/>
将参数的名称替换成“0”和“1”,也就是参数的索引。因为在XML中不允许数字作为属性的第一个字符,因此必须要添加一个下划线来作为前缀。
【p-命名空间】
c-命名空间通过构造器注入的方式来配置bean,p-命名空间则是用setter的注入方法来配置bean,同样的,需要引入声明。

通过p-命名空间来设置属性
<!-- 引入p-命名空间之前 --> <bean name="student1" class="pojo.Student"> <property name="id" value="1" /> <property name="name" value="学生1"/> </bean> <!-- 引入p-命名空间之后 --> <bean name="student2" class="pojo.Student" p:id="2" p:name="学生2"/>
但是需要先删掉Student类中的构造函数,不然XML约束会提示配置<contructor-arg>元素。
同样的,如果属性需要注入其他Bean的话也可以在后面跟上-ref:
<bean name="student2" class="pojo.Student" p:id="2" p:name="学生2" p:cdCard-ref="cdCard1"/>
【util-命名空间】
工具类的命名空间,可以简化集合类元素的配置,同样的需要引入其声明。

引入前后的变化
<!-- 引入util-命名空间之前 --> <property name="list"> <list> <ref bean="bean1"/> <ref bean="bean2"/> </list> </property> <!-- 引入util-命名空间之后 --> <util:list id="list"> <ref bean="bean1"/> <ref bean="bean2"/> </util:list>
<util:list>只是util-命名空间中的多个元素之一,下标提供了util-命名空间提供的所有元素。
| 元素 | 描述 |
|---|---|
<util:constant> |
引用某个类型的 public static 域,并将其暴露为 bean |
<util:list> |
创建一个 java.util.List 类型的 bean,其中包含值或引用 |
<util:map> |
创建一个 java.util.map 类型的 bean,其中包含值或引用 |
<util:properties> |
创建一个 java.util.Properties 类型的 bean |
<util:property-path> |
引用一个 bean 的属性(或内嵌属性),并将其暴露为 bean |
<util:set> |
创建一个 java.util.Set 类型的 bean,其中包含值或引用 |
引入其他配置文件
在实际开发中,随着应用程序规模的增加,系统中<bean>元素配置的数量也会大大增加,导致applicationContext.xml配置文件变得非常臃肿难以维护。
解决方法:让applicationContext.xml文件包含其他配置文件即可,使用<import>元素引入其他Spring配置文件。
<import resource="bean.xml" />
隐式的Bean发现机制和自动装配
这种方式是采用注解(annotation)的方式去装配Bean,这样可以减少XML的配置,当配置多的时候,臃肿难以维护;功能更加强大,既能实现XML的功能,也提供了自动装配的功能,采用了自动装配后,程序员开发需要做的决断就减少了。
在spring中,它提供了两种方式来让Spring IoC容器发现bean:
- 组件扫描:通过定义资源的方式,让Spring Ioc容器扫描对应的包,从而把bean装配进来。
- 自动装配:通过注解定义,使得一些依赖关系可以通过注解完成。
使用@Component装配Bean
package pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component(value = "student1") public class Student { @Value("1") int id; @Value("student_name_1") String name; // getter and setter }
- @Component注解:表示Spring IoC会把这个类扫描成一个bean实例,而其中的value属性代表这个类在Spring中的id,这就相当于在XML中定义的Bean的id:<bean id="student1" class="pojo.Student"/>也可以简单写成@Component("Student1"),甚至直接写成@Component,对于不写的,Spring IoC容器就默认以类名来命名作为id,只不过首字母小写,配置到容器中。
- @Value注解:表示值的注入,跟在XML中写value属性是一样的。
注解装配类似于XML的声明
<bean name="student1" class="pojo.Student"> <property name="id" value="1" /> <property name="name" value="student_name_1"/> </bean>
但是注解声明了这个类,并不能进行任何的测试,因为Spring IoC并不知道这个Bean的存在,这就需要使用StudentConfig类去告诉Spring IoC:
package pojo; import org.springframework.context.annotation.ComponentScan; @ComponentScan("com.company") public class StudentConfig { }
使用Spring 定义好的Spring IoC容器的实现类--AnnotationConfigApplicationContext去生成IoC容器。
ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class); Student student = (Student) context.getBean("student1", Student.class); student.printInformation();
缺点:对于@ComponentScan注解,它只是扫描所在包的java类,但是更多时候希望的是可以扫描指定的类;并且@Value注解只能注入简单的值。
@Component注解存在着两个配置项:
- basePackages:它可以配置一个java包的数组,Spring会根据它的配置扫描对应的包和子包,将配置的Bean装配进来。
- basePackageClasses:它可以配置多个类,Spring会根据配置的类所在的包,为包和子包进行扫描装配对应配置的Bean。
package pojo; import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackages = "pojo") public class StudentConfig { } // ———————————————————————————————————— package pojo; import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackageClasses = pojo.Student.class) public class StudentConfig { }
@Autowired自动装配
自动装配是一种Spring 自己发现对应的Bean,自动完成装配工作的方式。Spring会根据类型去寻找定义的Bean然后将其注入。
@Qualifier注解与@AutoWired注解一起使用,用来表示将指定的Bean对象作为属性值注入到目标Bean中。
1.StudentService接口
package service; public interface StudentService { public void printStudentInfo(); }
2.为上面的接口创建一个StudentServiceImp实现类
package service; import org.springframework.beans.factory.annotation.Autowired; import pojo.Student; @Component("studentService") public class StudentServiceImp implements StudentService { @Autowired @Qualifier("student") private Student student = null; // getter and setter public void printStudentInfo() { System.out.println("学生的 id 为:" + student.getName()); System.out.println("学生的 name 为:" + student.getName()); } }
3.测试类
// 第一步:修改 StudentConfig 类,告诉 Spring IoC 在哪里去扫描它: package pojo; import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackages = {"pojo", "service"}) public class StudentConfig { } // 或者也可以在 XML 文件中声明去哪里做扫描 <context:component-scan base-package="pojo" /> <context:component-scan base-package="service" /> // 第二步:编写测试类: package test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import pojo.StudentConfig; import service.StudentService; import service.StudentServiceImp; public class TestSpring { public static void main(String[] args) { // 通过注解的方式初始化 Spring IoC 容器 ApplicationContext context = new AnnotationConfigApplicationContext(StudentConfig.class); StudentService studentService = context.getBean("studentService", StudentServiceImp.class); studentService.printStudentInfo(); } }
在Java的接口和类中实现配置
使用@Bean注解装配Bean
@Component装配Bean的问题:只能注解在类上,当需要使用引用第三方包的(jar文件),而且往往并没有这些包的源码,这时候将无法为这些包的类加入@Component注解,让它们变成开发环境中的Bean资源。
解决方法:使用@Bean注解,注解到方法之上,使其成为Spring中返回对象为Spring的Bean资源。
package pojo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class BeanTester { @Bean(name = "testBean") public String test() { String str = "测试@Bean注解"; return str; } }
注意:@Configuration注解相当于XML文件的根元素,必须要,有了才能解析其中的@Bean注解。
在测试类中编写代码,从Spring IoC容器中获取到这个Bean:
// 在 pojo 包下扫描 ApplicationContext context = new AnnotationConfigApplicationContext("pojo"); // 因为这里获取到的 Bean 就是 String 类型所以直接输出 System.out.println(context.getBean("testBean"));
@Bean注解的配置项中包含四个配置项
- name:是一个字符串数组,允许配置多个BeanName。
- autowire:表明是否是一个引用的Bean对象,默认值Autowire.NO。
- initMethod:自定义初始化方法。
- destoryMethod:自定义销毁方法。
使用@Bean注解的好处就是能够动态获取一个Bean对象,能够根据环境不同得到不同的Bean对象。或者说将Spring和其他组件分离(其他组件不依赖Spring,但是又想Spring管理生产的Bean)。
Bean的作用域
在默认的情况下,Spring IoC容器只会对一个Bean创建一个实例,但是有时候,希望能够通过Spring IoC容器获取多个实例,可以通过@Scope注解或者<bean>元素中的scope属性来设置。
// XML 中设置作用域 <bean id="" class="" scope="prototype" /> // 使用注解设置作用域 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Spring 提供了5种作用域,它会根据情况来决定是否生成新的对象:
- Singleton(单例):在Spring IoC容器中仅存在一个Bean实例(默认的scope)
- prototype(多例):每次从容器中调用时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XXXBean():不会在容器启动时创建对象。
- request(请求):用于web开发,将Bean放入request范围,request.setAttribute("XXX"),在同一个request获得同一个Bean。
- session(会话):用于web开发,将Bean放入session范围,在同一个session获得同一个Bean。
- globalSession(全局会话):一般用于Porlet应用环境,分布式系统存在全局session概念(单点登录),如果不是porlet环境,globalSession等同于Session。
posted on
浙公网安备 33010602011771号