今天突然想总结一下spring自动装配,一下就是总结内容:
1.什么是自动装配
spring的Reference文档中给出的定义是:
The Spring container can autowire relationships between collaborating beans. You can allow Spring to resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext.
翻译成中文大致的意思是:
Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。你可以自
动让Spring通过检查ApplicationContext中的内容,来替我们指定bean的协作者(其他被依赖的bean)。
2.自动装配的优缺点:
优点:1).Autowiring can significantly reduce the need to specify properties or constructor arguments. (Other mechanisms such as a bean template discussed elsewhere in this chapter are also valuable in this regard.)
2).Autowiring can update a configuration as your objects evolve. For example, if you need to add a dependency to a class, that dependency can be satisfied automatically without you needing to modify the configuration. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.
缺点:1).Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire so-called simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
2).Autowiring is less exact than explicit wiring. Although, as noted in the above table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results, the relationships between your Spring-managed objects are no longer documented explicitly.
3).Wiring information may not be available to tools that may generate documentation from a Spring container.
4).Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Maps, this is not necessarily a problem. However for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
3.自动装配类型
spring的Reference文档中给出了如下几类自动装配类型:
Table 5.2. Autowiring modes
Mode | Explanation |
---|---|
no | (Default) No autowiring. Bean references must be defined via a |
byName | Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named |
byType | Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens;the property is not set. |
constructor | Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. |
下面让我们来看看Spring为我们提供的自动装配有那些(通过指定元素的)
1).no 默认装配模式,表示不进行装配,需要程序员自己去维护bean与bean之间的关系。
2).byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。
3).byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生,也可以通过设置dependency-check="objects"让Spring抛出异常。
4).constructor 与byType方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。
5).autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式,否则采用constructor。
4.代码示例:
4.1).示例准备:
Person.java
package test.model;
public class Person {
private String name;
private String address;
private int age;
private Pet pet;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public void sayHi(){
System.out.println("Hello,My Friends!");
}
}
Pet.java
package test.model;
public class Pet {
private String nickName;
private String category;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public void sayHello() {
System.out.println("Hello,I am a pet!");
}
}
Test01.java
package test.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.model.Person;
public class Test01 {
public static void main(String[] args){
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person=(Person) ac.getBean("person");
person.sayHi();
System.out.println("=====================");
person.getPet().sayHello();
}
}
4.2).使用默认自动装配,即不进行自动装配,系统将不会去容器中自动装配相关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-3.0.xsd">
<bean id="person" class="test.model.Person" />
<bean id="pet" class="test.model.Pet" />
</beans>
运行效果如下:
Hello,My Friends!
=====================
Exception in thread "main" java.lang.NullPointerException
at test.test.Test01.main(Test01.java:15)
4.3).使用byName进行自动装配,系统将会去容器中查找和属性名相同的id的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-3.0.xsd">
<bean id="person" class="test.model.Person" autowire="byName" />
<bean id="pet" class="test.model.Pet" autowire="byName"/>
</beans>
运行效果如下:
Hello,My Friends!
=====================
Hello,I am a pet!
4.4).使用byType进行自动装配,系统将会去容器中查找和属性类型相同的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-3.0.xsd">
<bean id="person" class="test.model.Person" autowire="byType" />
<bean id="pet1" class="test.model.Pet" autowire="byType"/>
</beans>
运行效果如下:
Hello,My Friends!
=====================
Hello,I am a pet!
注意:当容器中有多个相同类型的bean时,spring容器将不知道选择哪个bean进行装配,则系统将会报错
<?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-3.0.xsd">
<bean id="person" class="test.model.Person" autowire="byType" />
<bean id="pet1" class="test.model.Pet" autowire="byType"/>
<bean id="pet2" class="test.model.Pet" autowire="byType"/>
</beans>
运行效果如下:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in class path resource [applicationContext.xml]: Unsatisfied dependency expressed through bean property 'pet': : No unique bean of type [test.model.Pet] is defined: expected single matching bean but found 2: [pet1, pet2];
4.5).采用constructor进行自动装配,Person.java中增加显式构造器,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-3.0.xsd">
<bean id="person" class="test.model.Person" autowire="constructor"/>
<bean id="pet1" class="test.model.Pet" autowire="constructor"/>
</beans>
Person.java
package test.model;
public class Person {
private String name;
private String address;
private int age;
private Pet pet;
public Person(Pet pet){
this.pet=pet;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public void sayHi(){
System.out.println("Hello,My Friends!");
}
}
4.6).采用autodect进行自动装配时,系统将会从byType和constructor两种自动装配方法中选取一种进行自动装配,首先尝试使用constructor来自动装配,然后再使用byType方式。但是在做这个实验的时候没有成功,报出如下错误:
Caused by: org.xml.sax.SAXParseException: cvc-enumeration-valid: Value 'autodetect' is not facet-valid with respect to enumeration '[default, no, byName, byType, constructor]'. It must be a value from the enumeration.
我的spring版本为spring-3.2.M2.
4.7).配置默认的装配方式,其实我们默认的装配方式是在<beans>标签中配置的,默认是不显示的,现在可以通过在<beans>标签中显式配置默认使用byName进行自动装配
<?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-3.0.xsd"
default-autowire="byName">
<bean id="person" class="test.model.Person" />
<bean id="pet" class="test.model.Pet" />
</beans>
结束语:这篇博文是自己对spring自动装配的一次总结,博文中的内容可能还出现理解不正确或表达错误的地方,希望大家能指出来,共同提高,谢谢!