spring的第二天
在昨天简单的介绍了一下spring,那么今天接着继续介绍。
- spring值的注入
- 自动装配【autowire】
- 引用资源
- applicationContext和beanFactory的关系
spring的值的注入
在spring的第一天里面我介绍了spring基本类型值的注入以及引用类型值的注入,那么这次我们讨论数组
,list
,map
值的注入问题
首先有一个Person类
package com.weno.bean;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
然后有一个Persons的类
package com.weno.bean;
import java.util.List;
public class Persons {
private List<Person> personList;
public List<Person> getPersonList() {
return personList;
}
public void setPersonList(List<Person> personList) {
this.personList = personList;
}
@Override
public String toString() {
return "Persons{" +
"personList=" + personList +
'}';
}
}
-
lsit
在xml文件中
<bean id="persons" class="com.weno.bean.Persons"> <property name="personList"> <list> <!-- 使用外部bean则为<ref bean="***"/>--> <bean class="com.weno.bean.Person"> <property name="name" value="张三"/> <property name="age" value="14"/> </bean> <bean class="com.weno.bean.Person"> <property name="name" value="李四"/> <property name="age" value="18"/> </bean> </list> </property> </bean>
-
数组
注入数组元素和注入
list
元素是一样的,都是使用<list>标签,就不介绍了。 -
set
<bean id="persons" class="com.weno.bean.Persons"> <property name="personSet"> <set> <bean class="com.weno.bean.Person"> <property name="name" value="张三"/> <property name="age" value="14"/> </bean> <bean class="com.weno.bean.Person"> <property name="name" value="李四"/> <property name="age" value="18"/> </bean> </set> </property> </bean>
然后有个好神奇的现象,将<set> 标签换成<list>竟然也可以完美运行。
-
map
<bean class="com.weno.bean.Persons" id="persons"> <property name="map"> <map> <!-- 使用外部bean <entry key="person1" value-ref="***"/> --> <entry key="person1"> <bean class="com.weno.bean.Person"> <property name="name" value="张三"/> <property name="age" value="14"/> </bean> </entry> <entry key="person2"> <bean class="com.weno.bean.Person"> <property name="name" value="李四"/> <property name="age" value="17"/> </bean> </entry> </map> </property> </bean>
当然,在这集中集合中,我们既可以引用基本类型,也可以使用引用类型,在使用引用类型中,我们既可以使用外部bean的方式去使用,也可以使用内部Bean的方式去引用。
自动装配
spring的自动装配的默认值为no,也就是不进行自动装配
spring的自动装配分为:
- byType 按照数据类型注入
- byName 按照pojo对应的属性名字进行匹配
- byConstruct
- 优先按照类型进行注入,如果匹配到一个,就直接注入,如果不止一个,就按照名字注入,如果一个都找不到,则注入失败。
- default(默认值)
如果在上面的Person类里面再加上了一个Teacher。
定义Teacher的类:
public class Teacher {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
-
byName
<bean id="person" class="com.weno.bean.Person" autowire="byName"> <!-- 通过名字自动装配 --> <property name="name" value="王五"/> <property name="age" value="18"/> </bean> <bean id="teacher" class="com.weno.bean.Teacher"> <property name="name" value="老师"/> </bean>
如果这时候将结果进行输出会怎样?
Person{name='王五', age=18, teacher=Teacher{name='老师'}}
在这里自动的将treacher装配进来了。这个是根据名字进行自动加载的,接下来看看
byType
. -
byType
<bean id="person" class="com.weno.bean.Person" autowire="byType"> <!-- 通过类型进行导入 --> <property name="name" value="王五"/> <property name="age" value="18"/> </bean> <bean id="teacher1" class="com.weno.bean.Teacher"> <property name="name" value="老师"/> </bean>
Question:
- 那么
byType
和byName
有什么区别呢?
byType对于名字没有要求,在上面的代码中,即使id为teacher1
,也可以成功导入,而byName却不行。 - 如果有多个相同类型的bean会怎么导入,怎么控制导入?
如果有多个相同的bean,byType导入会报错。Unsatisfied dependency expressed through bean property 'teacher': No qualifying bean of type [com.weno.bean.Teacher] is defined: expected single matching bean but found 2:
<bean id="teacher1" class="com.weno.bean.Teacher" primary="true"> <!-- primary默认是false,但是好像在某些版本默认是false --> <property name="name" value="大老师"/> </bean> <bean id="Teacher" class="com.weno.bean.Teacher"> <property name="name" value="小老师"/> </bean>
Person{name='王五', age=18, teacher=Teacher{name='大老师'}}
- 那么
-
byConstruct
与byType的方式类似,不同之处在于它应用于
构造器
参数。优先按照类型进行注入,如果匹配到一个,就直接注入,如果不止一个,就按照名字注入,如果一个都找不到,则注入失败。在person类中加入构造方法
public Person(Teacher teacher) { this.teacher = teacher; } // 注意,这个也要保留 public Person() { }
<bean id="person" class="com.weno.bean.Person" autowire="constructor"> <property name="name" value="王五"/> <property name="age" value="18"/> </bean> <bean id="teacher" class="com.weno.bean.Teacher"> <property name="name" value="大老师"/> </bean> <bean id="teacher2" class="com.weno.bean.Teacher"> <property name="name" value="小老师"/> </bean>
在这两个中,按照第一个会装配,而第二个不会装配。【ps:当匹配到多个时,优先按照名字装配,如ru果有多个,名字又不匹配,就报错】
引入资源
-
引入其他xml文件
试想一下,如果我们将所有的配置全部写在一个文件中,那么该多么庞杂,且不利于项目合作,这时候我们就可以使用一个主文件,目的是来导入其他文件。<!--导入其他--> <import resource="classpath:personConfig.xml"/>
如果我们需要导入很多xml文件怎么办,这时候我们可以使用通配符
*
来导入
假如在一个manager.xml
文件中引入资源spring-person,spring-test,这时,我们可以这样做:<!-- 注意,使用通配符时,不要将总文件包含! 如果在这里将manager.xml命名为spring-manager.xml, 那么就会报错 --> <import resource="spring-*.xml"/>
applicationContext和beanFactory的关系
BeanFactory是Spring容器最基本的接口,负责读取bean的配置文件,管理bean的加载和实例化。
而Application是BeanFactory的子接口,对BeanFactory进行了扩展,比如AOP,Web。
- 提供了支持国际化的文本消息
- 统一的资源文件读取方式
- 已在监听器中注册的bean的事件
区别:
- 使用BeanFactory的时候,不会预处理Bean,所以及时正确的创建了BeanFactory实例,在getBean的时候仍任可能报错抛出异常。而在applicationContext中,会默认初始化所有的Bean,所以在前期applicationContext会有较大的开销,但是获取完后却能得到较好的性能。当然也可以使用
lazy-init
,阻止该bean的初始化。 - BeanFactory需要手动注册,而ApplicationContext是自动注册的。