依赖注入DI(Dependency Injection)的两种方式
Spring中给Bean属性赋值有两种方式:
- 构造注入(Constructor-based Dependency Injection):通过构造方法给bean的属性赋值。所以要求bean的类中必须提供对应参数的构造方法。相当于以前创建对象时new Student(1,"张三");
- 设值注入,又称setter注入(Setter-based Dependency Injection):通过Bean的setter 方法赋值。所以要求Bean中属性必须提供setter方法。相当于以前的:Student student= new Student(); student.setld(1);student.setName("张三");
- 接下来通过将上次对工厂的测试方法一分为三进行演示

构造注入
- 必须在Bean中提供有参构造方法(无参构造方法最好也提供上,这个位置不用,但是其他位置如果没有通过构造注入,默认是调用无参构造的,会发生异常)
添加有参构造
java
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
配置Spring
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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory" factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂-->
<bean id="studentFactory" class="com.tianshi.factory.StudentInstanceFactory"></bean>
<bean id="studentWithInstanceFactory" class="com.tianshi.domain.Student"
factory-bean="studentFactory" factory-method="getStudent">
</bean>
<!--配置FactoryBean工厂-->
<bean id="studentWithFactoryBean" class="com.tianshi.factory.StudentFactoryBean">
</bean>
</beans>
测试
java
package com.tianshi.test;
import com.tianshi.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentWithStaticFactoryTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student=(Student)applicationContext.getBean("studentWithStaticFactory");
System.out.println(student);
}
}

C名称空间注入
- Spring 框架提供更加方便的配置方案,此注入方式基于构造方法, 仅简化了配置,此配置方案在一定程度上,降低了配置文件的可读性
添加有参构造
java
/**
* 常用4:实例工厂+多例
* 用途:不同工厂做不同初始化、策略模式、Spring 原型 Bean
*/
public Student getStudent(){
return new Student();
}
public Student getStudent(Integer id,String name){
return new Student(id,name);
}
java
/**
* 常用5:实例工厂+单例
* 用途:一个工厂实例对应一个唯一对象
*/
private Student student;
//无参构造
public StudentInstanceFactory() {}
//无参获取
public Student getStudent() {
if (student == null) {
student = new Student();
}
return student;
}
//有参获取
public Student getStudent(Integer id,String name) {
if (student == null) {
student = new Student(id, name);
}
return student;
}
配置Spring
记得在beans前面加上这一行,即提供名字空间配置信息
xml
xmlns:c="http://www.springframework.org/schema/c"
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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory"
factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂-->
<!--C名称空间注入
基于参数索引的配置:
c:_索引数="值" 注入简单类型数据值
c:_索引数-ref="bean的id" 注入Spring容器中的其他的bean对象
基于参数名的配置:
c:参数名="值" 注入简单类型的数据值
c:参数名="bean的id" 注入Spring容器中其他的bean对象
-->
<bean id="studentFactory" class="com.tianshi.factory.StudentInstanceFactory"/>
<bean id="studentWithInstanceFactory" class="com.tianshi.domain.Student"
factory-bean="studentFactory" factory-method="getStudent" c:_0="101" c:name="李四">
</bean>
<!--配置FactoryBean工厂-->
<bean id="studentWithFactoryBean" class="com.tianshi.factory.StudentFactoryBean">
</bean>
</beans>
测试
java
package com.tianshi.test;
import com.tianshi.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentWithInstanceFactoryTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("studentWithInstanceFactory");
System.out.println(student);
}
}

设值注入
设值注入要求类型中必须提供 Setter 方法,且一般配合无参构造完成注入
Student类(提供Serializable标记接口告诉JVM该类可被序列化反序列化)
java
package com.tianshi.domain;
import java.io.Serializable;
import java.util.Objects;
public class Student implements Serializable {
private Integer id; //身份唯一标识
private String name; //姓名
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer id() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(id, student.id) && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
泛型接口FactoryBean重写
- 使用有参注入必须提供setter方法,该泛型接口不认你写的重载方法
java
package com.tianshi.factory;
import com.tianshi.domain.Student;
import org.springframework.beans.factory.FactoryBean;
/**
* 基于Spring定义的工厂Bean接口,定义工厂类型
* 接口泛型代表当前工厂生产的产品的类型
*
* 此种方式让代码和Spring框架耦合到一起,如果不适用spring框架,当前代码不可用
*/
public class StudentFactoryBean implements FactoryBean<Student> {
//使用有参注入必须提供setter方法,该泛型接口不认你写的重载方法
private Integer id;
private String name;
public Integer id() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 工厂方法
* @return 产品对象
* @throws Exception
*/
@Override
public Student getObject() throws Exception {
return new Student(id, name);
}
/**
* 工厂生产的产品是什么
* @return 产品类型对象
*/
@Override
public Class<?> getObjectType() {
return Student.class;
}
}
配置Spring
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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory"
factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂-->
<!--C名称空间注入
基于参数索引的配置:
c:_索引数="值" 注入简单类型数据值
c:_索引数-ref="bean的id" 注入Spring容器中的其他的bean对象
基于参数名的配置:
c:参数名="值" 注入简单类型的数据值
c:参数名="bean的id" 注入Spring容器中其他的bean对象
-->
<bean id="studentFactory" class="com.tianshi.factory.StudentInstanceFactory" c:_0="101" c:name="李四"/>
<bean id="studentWithInstanceFactory" class="com.tianshi.domain.Student"
factory-bean="studentFactory" factory-method="getStudent"/>
<!--配置FactoryBean工厂-->
<!--设值注入
标签属性:
name:要注入数据的property属性名
value:为属性赋值(简单数据类型)
ref:为属性赋值(引用数据类型)
-->
<bean id="studentWithFactoryBean" class="com.tianshi.factory.StudentFactoryBean">
<property name="id" value="102"/>
<property name="name" value="王五"/>
</bean>
</beans>
测试
java
package com.tianshi.test;
import com.tianshi.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentWithFactoryBeanTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("studentWithFactoryBean");
System.out.println(student);
}
}

P名称空间注入
配置Spring
记得在beans前面加上这一行,即提供名字空间配置信息
xml
xmlns:p="http://www.springframework.org/schema/p"
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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory"
factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂-->
<!--C名称空间注入
基于参数索引的配置:
c:_索引数="值" 注入简单类型数据值
c:_索引数-ref="bean的id" 注入Spring容器中的其他的bean对象
基于参数名的配置:
c:参数名="值" 注入简单类型的数据值
c:参数名="bean的id" 注入Spring容器中其他的bean对象
-->
<bean id="studentFactory" class="com.tianshi.factory.StudentInstanceFactory" c:_0="101" c:name="李四"/>
<bean id="studentWithInstanceFactory" class="com.tianshi.domain.Student"
factory-bean="studentFactory" factory-method="getStudent"/>
<!--配置FactoryBean工厂-->
<!--设值注入
标签属性:
name:要注入数据的property属性名
value:为属性赋值(简单数据类型)
ref:为属性赋值(引用数据类型)
-->
<bean id="studentWithFactoryBean1" class="com.tianshi.factory.StudentFactoryBean">
<property name="id" value="102"/>
<property name="name" value="王五"/>
</bean>
<!--P名称空间注入
仅基于参数名,无基于索引:
p:属性名 = "简单数据"
p:属性名-ref = "引用数据,其他bean标签的id"
-->
<bean id="studentWithFactoryBean2" class="com.tianshi.factory.StudentFactoryBean" p:id="103" p:name="赵六"/>
</beans>
测试
java
package com.tianshi.test;
import com.tianshi.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentWithFactoryBeanTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//第一个工厂
Student student1 = (Student) applicationContext.getBean("studentWithFactoryBean1");
System.out.println(student1);
//第二个工厂
Student student2 = (Student) applicationContext.getBean("studentWithFactoryBean2");
System.out.println(student2);
}
}

各种类型属性的注入配置方式
- 无论是构造注入还是设值注入都提供了 value 和 ref 进行设置值,这两个属性只能给属性赋予简单数据类型或其他 bean 的引用
- 如果类的属性是数组、集合等类型需要通过下面 方式进行设置,这些标签都是或的子标签
- 一旦使用了子标签方式,就不能对或设置 value 属性或 ref 属性,且需要在 Student 类中提供对应名称、对应类型的属性
新增Book类型
java
package com.tianshi.domain;
public class Book {
private Integer id;
private String name;
public Book() {
}
public Book(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer id() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
修改Student类型
java
package com.tianshi.domain;
import java.io.Serializable;
import java.util.*;
public class Student implements Serializable {
private Integer id; //身份唯一标识
private String name; //姓名
//数组
private String[] hobbies;
//List集合
private List<Book> books;
//Set集合
private Set<String> set;
//Map集合
private Map<Integer,String> map;
//引用类型
private Book book;
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer id() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> books() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public String[] hobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
public Set<String> set() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Map<Integer, String> map() {
return map;
}
public void setMap(Map<Integer, String> map) {
this.map = map;
}
public Book book() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", hobbies=" + Arrays.toString(hobbies) +
", books=" + books +
", set=" + set +
", map=" + map +
", book=" + book +
'}';
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(id, student.id) && Objects.equals(name, student.name) && Objects.deepEquals(hobbies, student.hobbies) && Objects.equals(books, student.books) && Objects.equals(set, student.set) && Objects.equals(map, student.map) && Objects.equals(book, student.book);
}
@Override
public int hashCode() {
return Objects.hash(id, name, Arrays.hashCode(hobbies), books, set, map, book);
}
}
Book实例工厂
java
package com.tianshi.factory;
import com.tianshi.domain.Book;
import com.tianshi.domain.Student;
public class BookInstanceFactory {
private Book book;
public BookInstanceFactory() {
}
public Book getBook() {
if (book == null) {
book = new Book();
}
return book;
}
public Book getBook(Integer id,String name) {
if (book == null) {
book = new Book(id,name);
}
return book;
}
}
配置Spring
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<!-- //唯一一个静态工厂(构造注入)-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory"
factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂两个-->
<!--C名称空间注入
基于参数索引的配置:
c:_索引数="值" 注入简单类型数据值
c:_索引数-ref="bean的id" 注入Spring容器中的其他的bean对象
基于参数名的配置:
c:参数名="值" 注入简单类型的数据值
c:参数名="bean的id" 注入Spring容器中其他的bean对象
-->
<!-- //第一个实例工厂(C名称空间注入)-->
<bean id="studentFactory1" class="com.tianshi.factory.StudentInstanceFactory"/>
<bean id="studentWithInstanceFactory1" class="com.tianshi.domain.Student"
factory-bean="studentFactory1" factory-method="getStudent" c:_0="101" c:name="李四"/>
<!-- //Book的实例工厂-->
<bean id="bookFactory" class="com.tianshi.factory.BookInstanceFactory"/>
<bean id="bookWithInstanceFactory" class="com.tianshi.domain.Book"/>
<!-- //第二个实例工厂(各种类型的属性注入的配置)-->
<bean id="studentFactory2" class="com.tianshi.factory.StudentInstanceFactory"/>
<bean id="studentWithInstanceFactory2" class="com.tianshi.domain.Student"
factory-bean="studentFactory2" factory-method="getStudent">
<property name="id" value="105"/>
<property name="name" value="王"/>
<!--数组array标签,一个标签代表一个数组-->
<property name="hobbies">
<array>
<!--数组中的简单数据,按照属性依次从0开始赋值-->
<value>0下标</value>
<value>1下标</value>
<value>2下标</value>
<!--ref,数组中的一个引用类型数据,按照配置属性依次从0下标开始赋值-->
<!--<ref bean="beanId"></ref>-->
</array>
</property>
<!--List集合,list标签,一个标签代表一个集合对象-->
<property name="books">
<list>
<!--0下标位置对象-->
<ref bean="bookWithInstanceFactory"></ref>
<!--配置一个局部的bean对象,不需要命名(不写id),局部有效-->
<bean class="com.tianshi.domain.Book">
<property name="id" value="2"></property>
<property name="name" value="算法导论"/>
</bean>
<ref bean="bookWithInstanceFactory"></ref>
</list>
</property>
<!--Set集合,set标签-->
<property name="set">
<set>
<value>set值1</value>
<value>set值2</value>
<value>set值3</value>
</set>
</property>
<!--Map集合,map标签和entry子标签,一个map标签代表一个Map集合一个entry标签代表map中的一个键值对-->
<property name="map">
<map>
<!--entry有属性 key:简单类型键值,key-ref:引用类型键值
value:简单类型value值,value-ref:引用类型value值-->
<entry key="1" value="value1"></entry>
<entry key="2" value="value2"></entry>
<entry key="3" value="value3"></entry>
</map>
</property>
<!--引用类型属性,使用ref注入-->
<property name="book" ref="bookWithInstanceFactory"/>
</bean>
<!--配置FactoryBean工厂两个-->
<!--设值注入
标签属性:
name:要注入数据的property属性名
value:为属性赋值(简单数据类型)
ref:为属性赋值(引用数据类型)
-->
<!-- //第一个FactoryBean工厂(设值注入)-->
<bean id="studentWithFactoryBean1" class="com.tianshi.factory.StudentFactoryBean">
<property name="id" value="102"/>
<property name="name" value="王五"/>
</bean>
<!--P名称空间注入
仅基于参数名,无基于索引:
p:属性名 = "简单数据"
p:属性名-ref = "引用数据,其他bean标签的id"
-->
<!-- //第二个FactoryBean工厂(P名称空间注入)-->
<bean id="studentWithFactoryBean2" class="com.tianshi.factory.StudentFactoryBean" p:id="103" p:name="赵六"/>
</beans>
测试
java
package com.tianshi.test;
import com.tianshi.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentWithInstanceFactoryTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//实例工厂1
Student student1 = (Student) applicationContext.getBean("studentWithInstanceFactory1");
System.out.println(student1);
//实例工厂2
Student student2 = (Student) applicationContext.getBean("studentWithInstanceFactory2");
System.out.println(student2);
}
}

依赖注入方式的选择
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入 完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用 构造器注入
- 自己开发的模块推荐使用setter注入
依赖注入的自动装配
- 在Spring中,允许Bean的自动注入,loC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
- 自动装配有两种方式进行配置:局部配置(推荐)、全局配置
局部配置&全局配置
给book工厂注入,测试发现,使用ref引用类型的地方有了参数
xml
<!-- //Book的实例工厂-->
<bean id="bookFactory" class="com.tianshi.factory.BookInstanceFactory"/>
<bean id="bookWithInstanceFactory" class="com.tianshi.domain.Book" p:id="1" p:name="空"/>

<!--局部的依赖注入自动装配
在bean标签中,有属性 autowire,代表是否采用自动装配逻辑。
可以设置的值:
default : 默认的,此是默认值。默认策略就是全局策略
no : 不使用自动装配逻辑。
byName : 根据名字完成自动装配。当前bean中的property的名字和当前配置文件中bean的id如果一样,则自动注入
有可能,类型不匹配
byType : 根据类型完成自动装配。当前bean中的property的类型和当前配置文件中bean的类型如有一样,则自动注入
有可能,当前配置文件中有多个bean的类型和同一个property的类型相同,抛出异常。
最常用。一般情况下,一个配置文件,不会配置多个同类型bean
constructor : 构造器注入。扫描当前bean类型中的有参数构造方法,扫描构造方法的参数表,
基于先byType,再byName的顺序逻辑,在当前配置文件中匹配bean对象,调用构造方法注入。
-->
局部配置依赖全局配置
- 全局即beans(标签中追加default-autowire),局部即bean(标签中追加autowire),皆有五个值,详解如上
- 局部配置的优先级大于全局配置的优先级,全局使用byType,局部使用default/全局使用default,局部使用byType,注解掉使用ref属性的标签,仍然可以引用,完成自动装配
方法一:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
使用名字空间的时候,必须在根标签beans中,增加对应的配置内容,就是
xmlns:c="http://www.springframework.org/schema/c"
xml namespace = " 名字空间编写配置方案的描述内容,约束配置的方式。 "
p名字空间,必须配置 xmlns:p="http://www.springframework.org/schema/p"
全局自动装配策略在beans标签上增加属性。 default-autowire
属性的可配置值和局部自动装配一样,除default外,其他和局部自动装配策略含义完全相同。
default : 默认策略,就是不自动装配。等同no。
no
byType
byName
constructor
建议直接配置全局策略。常用byType。在特定的bean标签上,可以做单独的设置。局部优先级更高。
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType">
<!--自动装配-->
<!--局部的依赖注入自动装配
在bean标签中,有属性 autowire,代表是否采用自动装配逻辑。
可以设置的值:
default : 默认的,此是默认值。默认策略就是全局策略
no : 不使用自动装配逻辑。
byName : 根据名字完成自动装配。当前bean中的property的名字和当前配置文件中bean的id如果一样,则自动注入
有可能,类型不匹配
byType : 根据类型完成自动装配。当前bean中的property的类型和当前配置文件中bean的类型如有一样,则自动注入
有可能,当前配置文件中有多个bean的类型和同一个property的类型相同,抛出异常。
最常用。一般情况下,一个配置文件,不会配置多个同类型bean
constructor : 构造器注入。扫描当前bean类型中的有参数构造方法,扫描构造方法的参数表,
基于先byType,再byName的顺序逻辑,在当前配置文件中匹配bean对象,调用构造方法注入。
-->
<bean id="student" class="com.tianshi.beans.Student" autowire="default">
<property name="id" value="100"/>
<property name="name" value="张三"/>
<!--<property name="book" ref="book"/>-->
</bean>
<bean id="book" class="com.tianshi.beans.Book">
<property name="id" value="100"/>
<property name="name" value="spring in action"/>
</bean>
<!--<bean id="book1" class="com.tianshi.beans.Book">
<property name="id" value="200"/>
<property name="name" value="thinking in java"/>
</bean>-->
<!--DI注入方式: 2. 设置注入,配合无参构造或有参构造都可以完成。 -->
<!--<bean id="student" class="com.tianshi.beans.Student">
<!– 设置注入,相关的配置标签是 property
标签属性:
name :要注入数据的property属性名是什么。
value : 为属性赋值,必须是简单类型数据
ref : 为属性赋值,必须是引用类型数据
–>
<property name="id" value="10"/>
<property name="name" value="王五"/>
<!–数组, array标签,一个标签代表一个数组–>
<property name="hobbies">
<array>
<!–数组中的一个简单数据,按照配置属性依次从0下标开始赋值–>
<value>0下标</value>
<value>1下标</value>
<value>2下标</value>
<!–ref,数组中的一个引用类型数据,按照配置属性依次从0下标开始赋值–>
<!–<ref bean="beanId"></ref>–>
</array>
</property>
<!–List集合, list标签,一个标签代表一个集合对象–>
<property name="books">
<list>
<!–0下标位置对象–>
<ref bean="book"></ref>
<!–配置一个局部的bean对象,不需要命名(不写id),局部有效。–>
<bean class="com.tianshi.beans.Book">
<property name="id" value="20"/>
<property name="name" value="Spring框架技术"/>
</bean>
<!–value只能赋予简单类型数据。–>
<!–<value>简单数据值</value>–>
</list>
</property>
<!–Set集合:set标签–>
<property name="set" >
<set>
<!–也有ref和bean配置方式。参考list配置–>
<value>set值1</value>
<value>set值2</value>
<value>set值3</value>
</set>
</property>
<!–Map集合:map标签和entry子标签。一个map标签代表一个Map集合。一个entry标签代表map中的一个键值对–>
<property name="map">
<map>
<!–entry有属性 key:简单类型键值,key-ref:引用类型键值
value:简单类型value值,value-ref:引用类型value值–>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
<entry key="key3" value="value3"></entry>
</map>
</property>
<!–引用类型属性,使用ref注入–>
<property name="book" ref="book"></property>
</bean>-->
<!--<bean id="book" class="com.tianshi.beans.Book">
<property name="id" value="10"/>
<property name="name" value="spring in action"/>
</bean>
-->
<!-- p名字空间配置方式:
p:属性名 = "简单数据"
p:属性名-ref = "引用数据,其他bean标签的id"
-->
<!--<bean id="studentWithPNS" class="com.tianshi.beans.Student"
p:id="20" p:name="赵六"></bean>-->
<!-- DI的注入方式: 1. 构造注入 -->
<!--<bean id="student" class="com.tianshi.beans.Student">
<!– 构造注入的配置方案,使用标签完成配置信息
index : 参数在构造方法参数表中的下表。从0开始计数。
name : 构造方法参数名称
type : 构造方法参数类型。
value : 要传入的构造方法参数值。注意,只能给八种基本类型和对应包装类和字符串赋值。统称简单类型。
ref : 要传入的构造方法参数。注意,只能给引用类型赋值。不是简单类型的。引用其他已经配置的bean的名字
建议使用 index + value 或 ref 即可。
如果有多个构造方法,参数表的数量一样,但是类型不同,建议使用 index + name + value 或 ref 完成配置。
value和ref只能使用一个。 index, name, type 可以同时使用。
–>
<constructor-arg index="0" name="id"
type="java.lang.Integer" value="1" />
<constructor-arg index="1" value="张三" />
</bean>-->
<!-- C名称空间配置
使用C名称空间后,标签bean新增属性。 c:xxxx,用于完成构造注入
c:_下标 : 从0开始。 简单类型赋值
c:_下标-ref : 从0开始。 引用类型赋值
c:构造方法参数名 : 简单类型赋值
c:构造方法参数名-ref : 引用类型赋值
-->
<!-- <bean id="studentWithCNS" class="com.tianshi.beans.Student"
c:_0="2" c:name="李四"></bean>-->
</beans>
方法二:
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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="default">
<!--Spring框架的核心配置文件-->
<!--一个bean标签就是一个domain对象,让Spring框架帮忙创建管理这个对象
id 唯一标识
class 类型的具体名称,必须写包名.类名
-->
<!-- <bean id="student" class="com.tianshi.domain.Student"/>-->
<!--配置静态工厂-->
<!-- //唯一一个静态工厂(构造注入)-->
<bean id="studentWithStaticFactory" class="com.tianshi.factory.StudentStaticFactory"
factory-method="getStudent">
<!--DI构造注入
用来确定给哪个属性赋值(可同时使用):
index:参数在构造参数表中的下标,从0开始计数
name:构造方法参数名称
type:构造方法参数类型
设置属性的值(只用一个):
value:要传入的构造方法参数值(简单类型)
ref:要传入的构造方法参数(引用类型)
建议用index+name+value/ref完成配置
-->
<constructor-arg index="0" name="id" value="100"/>
<constructor-arg index="1" name="name" value="小明"/>
</bean>
<!--配置实例工厂两个-->
<!--C名称空间注入
基于参数索引的配置:
c:_索引数="值" 注入简单类型数据值
c:_索引数-ref="bean的id" 注入Spring容器中的其他的bean对象
基于参数名的配置:
c:参数名="值" 注入简单类型的数据值
c:参数名="bean的id" 注入Spring容器中其他的bean对象
-->
<!-- //第一个实例工厂(C名称空间注入)-->
<bean id="studentFactory1" class="com.tianshi.factory.StudentInstanceFactory"/>
<bean id="studentWithInstanceFactory1" class="com.tianshi.domain.Student"
factory-bean="studentFactory1" factory-method="getStudent" c:_0="101" c:name="李四"/>
<!-- //Book的实例工厂-->
<bean id="bookFactory" class="com.tianshi.factory.BookInstanceFactory"/>
<bean id="bookWithInstanceFactory" class="com.tianshi.domain.Book" p:id="1" p:name="空"/>
<!-- //第二个实例工厂(各种类型的属性注入的配置)-->
<bean id="studentFactory2" class="com.tianshi.factory.StudentInstanceFactory"/>
<!--自动装配-->
<!--局部的依赖注入自动装配
在bean标签中,有属性 autowire,代表是否采用自动装配逻辑。
可以设置的值:
default : 默认的,此是默认值。默认策略就是全局策略
no : 不使用自动装配逻辑。
byName : 根据名字完成自动装配。当前bean中的property的名字和当前配置文件中bean的id如果一样,则自动注入
有可能,类型不匹配
byType : 根据类型完成自动装配。当前bean中的property的类型和当前配置文件中bean的类型如有一样,则自动注入
有可能,当前配置文件中有多个bean的类型和同一个property的类型相同,抛出异常。
最常用。一般情况下,一个配置文件,不会配置多个同类型bean
constructor : 构造器注入。扫描当前bean类型中的有参数构造方法,扫描构造方法的参数表,
基于先byType,再byName的顺序逻辑,在当前配置文件中匹配bean对象,调用构造方法注入。
-->
<bean id="studentWithInstanceFactory2" class="com.tianshi.domain.Student"
factory-bean="studentFactory2" factory-method="getStudent" autowire="byType">
<property name="id" value="105"/>
<property name="name" value="王"/>
<!--数组array标签,一个标签代表一个数组-->
<property name="hobbies">
<array>
<!--数组中的简单数据,按照属性依次从0开始赋值-->
<value>0下标</value>
<value>1下标</value>
<value>2下标</value>
<!--ref,数组中的一个引用类型数据,按照配置属性依次从0下标开始赋值-->
<!--<ref bean="beanId"></ref>-->
</array>
</property>
<!--List集合,list标签,一个标签代表一个集合对象-->
<property name="books">
<list>
<!--0下标位置对象-->
<ref bean="bookWithInstanceFactory"></ref>
<!--配置一个局部的bean对象,不需要命名(不写id),局部有效-->
<bean class="com.tianshi.domain.Book">
<property name="id" value="2"></property>
<property name="name" value="算法导论"/>
</bean>
<ref bean="bookWithInstanceFactory"></ref>
</list>
</property>
<!--Set集合,set标签-->
<property name="set">
<set>
<value>set值1</value>
<value>set值2</value>
<value>set值3</value>
</set>
</property>
<!--Map集合,map标签和entry子标签,一个map标签代表一个Map集合一个entry标签代表map中的一个键值对-->
<property name="map">
<map>
<!--entry有属性 key:简单类型键值,key-ref:引用类型键值
value:简单类型value值,value-ref:引用类型value值-->
<entry key="1" value="value1"></entry>
<entry key="2" value="value2"></entry>
<entry key="3" value="value3"></entry>
</map>
</property>
<!--引用类型属性,使用ref注入-->
<!-- <property name="book" ref="bookWithInstanceFactory"/>-->
</bean>
<!--配置FactoryBean工厂两个-->
<!--设值注入
标签属性:
name:要注入数据的property属性名
value:为属性赋值(简单数据类型)
ref:为属性赋值(引用数据类型)
-->
<!-- //第一个FactoryBean工厂(设值注入)-->
<bean id="studentWithFactoryBean1" class="com.tianshi.factory.StudentFactoryBean">
<property name="id" value="102"/>
<property name="name" value="王五"/>
</bean>
<!--P名称空间注入
仅基于参数名,无基于索引:
p:属性名 = "简单数据"
p:属性名-ref = "引用数据,其他bean标签的id"
-->
<!-- //第二个FactoryBean工厂(P名称空间注入)-->
<bean id="studentWithFactoryBean2" class="com.tianshi.factory.StudentFactoryBean" p:id="103" p:name="赵六"/>
</beans>
自动装配的特性
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,否则有发生异常的可能,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置 耦合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效