1、自动装配
可通过<beans.../>元素的default-autowire属性指定,也可通过<bean.../>元素的autowire属性指定。
自动装配可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。尽量少用!
autowire属性可以接受如下值:
- no:不使用自动装配。Bean依赖必须通过ref元素定义。这是默认的配置。
- byName:根据setter方法名来自动装配。Spring查找容器中全部Bean,
找出其中id属性与setter方法名去掉set前缀后同名的Bean来完成注入。
如果没有找到匹配的Bean实例,则Spring不会进行任何注入,也不报错。
- byType:根据setter方法形参类型来自动装配。BeanFactory查找容器中全部Bean,
如果正好有一个Bean类型与setter形参类型匹配,就自动注入这个Bean;
如果有多个这样的Bean,就抛出一个异常;NoUniqueBeanDefinitionException
如果没有找到匹配的Bean实例,则Spring不会进行任何注入,也不报错。
如果希望某个Bean不参与自动装配,可以指定autowire-candidate="false"
- constructor:与byType类似,区别是用于构造注入的参数。
如果BeanFactory中不是恰好有一个Bean与构造器参数类型相同,则会抛出一个异常。
- autodetect:BeanFactory根据Bean内部结构,决定使用constructor或byType。
如果找到一个默认的构造函数,那么就会应用byType。
(1)eg: byName
①beans.xml配置:
<bean id="dog" class="cony.domain.Dog">
<property name="kind" value="金毛犬"/>
</bean>
<bean id="dog2" class="cony.domain.Dog" >
<property name="kind" value="吉娃娃"/>
</bean>
<!-- setDog(Dog dog)方法会找类型为Dog的Bean,如果找到一个执行依赖注入 -->
<bean id="user" class="cony.domain.User" autowire="byName">
<property name="name" value="Tom" />
<property name="age" value="19" />
</bean>
②测试:
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
User user = appContext.getBean("user",User.class);
System.out.println(user);
③测试结果:
注入了id=dog的bean
(2)eg:byType
①beans.xml配置:
<bean id="dog" class="cony.domain.Dog" autowire-candidate="false">
<property name="kind" value="金毛犬"/>
</bean>
<bean id="dog2" class="cony.domain.Dog">
<property name="kind" value="吉娃娃"/>
</bean>
<!-- setDog(Dog dog)方法会找类型为Dog的Bean,如果找到一个执行依赖注入 -->
<bean id="user" class="cony.domain.User" autowire="byType">
<property name="name" value="Tom" />
<property name="age" value="19" />
</bean>
②测试:
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
User user = appContext.getBean("user",User.class);
System.out.println(user);
③测试结果:
假设去掉金毛犬上autowire-candidate="false"的配置,那么金毛犬也会参与自动装配,会出现以下错误:
(3)eg:constructor
①beans.xml配置:
<bean id="dog" class="cony.domain.Dog" >
<property name="kind" value="吉娃娃"/>
</bean>
<bean id="user" class="cony.domain.User" autowire="constructor">
<constructor-arg value="小方"/>
<constructor-arg value="18" type="int"/>
</bean>
②测试:
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
User user = appContext.getBean("user",User.class);
System.out.println(user);
③测试结果:
constructor与byType类似,也是只能有一个符合的bean。但在constructor中发现这样的情况:如果是下面代码,将会自动注入吉娃娃,没有报错,但如果将id=dog名称改为其他,则会报错:NoUniqueBeanDefinitionException。
所以我觉得可能是在constructor配置下,在出现多个bean时会采取byName的自动注入,如果找不到,才报错。
2、属性简化配置
注意:需要配置命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
把子元素变成属性
测试结果:setter的值覆盖了构造器设定的值
3、嵌套bean
4、集合
(1)User.java
public class User {
private String name;
private int age;
private Puppy dog;
private String[] nicknames;
private List<String> hobby;
private Set item;
private Map<String,Dog> dogs;
private Properties health;
public User(){
System.out.println("---调用无参构造器---");
}
public User(String name,int age,Puppy dog){
super();
System.out.println("---调用有参构造器---");
this.name = name;
this.age = age;
this.dog = dog;
}
......//setter、getter
}
(2)beans.xml
<bean id="dog" class="cony.domain.Puppy" p:kind="古代牧羊犬" />
<bean id="dog2" class="cony.domain.Puppy" p:kind="萌萌的柯基" />
<bean id="dinosaur" class="cony.domain.Dinosaur"
p:kind="霸王龙"/>
<bean id="user" class="cony.domain.User"
p:name="黄豆"
p:age="21"
p:dog-ref="dog"
>
<!-- setNicknames(String[] nicknames) -->
<property name="nicknames">
<list>
<value>猴子</value>
<value>华华</value>
</list>
</property>
<!-- setHobby(List<String> hobby) -->
<property name="hobby">
<list>
<value>吉他</value>
<value>烘焙</value>
</list>
</property>
<!-- setItem(Set item) -->
<property name="item">
<set>
<value>书包</value>
<value>铅笔</value>
<list>
<value>小鸭子</value>
<value>跳跳虎</value>
</list>
<ref bean="dog2"/>
<bean class="javax.swing.JFrame"
c:_0="myFrame"
p:visible="true"
/>
<set>
<value>Peppa pig</value>
</set>
</set>
</property>
<!-- setDogs(Map<String, Dog> dogs) -->
<property name="dogs">
<map>
<entry key="little child" value-ref="dog2"/>
<entry key="big girl" value-ref="dinosaur"/>
</map>
</property>
<!-- setHealth(Properties health) -->
<property name="health">
<props>
<prop key="身高">180</prop>
<prop key="体重">60kg</prop>
</props>
</property>
</bean>
(3)测试:
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans.xml");
User user = appContext.getBean("user",User.class);
System.out.println(user);
测试结果: