什么是自动装配
自动装配帮我们省去了 property标签配置操作,Spring会自动根据 属性名称,类型,构造器来进行自动注入。
例如不进行自动装配配置如下:
<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
通过属性名称自动装配配置如下:
<bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName"></bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
自动装配类型
Spring自动装配分为4种:
1. default
default 不进行自动装配 默认采用 default。
配置方式如下:
<bean autowire="default"></bean>
2. byName
通过名称进行自动装配。
配置方式如下:
<bean autowire="byName"></bean>
3. byType
通过注入Bean的类类型来进行匹配。
配置方式如下:
<bean autowire="byType"></bean>
4. constructor
通过构造器进行注入。
配置方式如下:
<bean autowire="constructor"></bean>
需要注意的是在spring2.5 时候还有一种类型autowire=“autodetect” 它表示优先执行构造器的方式如果构造器没有就执行byType 不过在spring3.0的时候就废除了
自动装配的具体实现
1 默认方式:
spring xml配置文件配置如下:
<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault" autowire="default">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserDefault类代码如下:
public class UserDefault {
private Country country;
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
}
Country 类代码如下:
public class Country {
private String name="CHINA";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
进行测试:
测试类代码如下:
@Test
public void userDefault() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserDefault user = (UserDefault)appliction.getBean("userDefault");
System.out.println("country:"+user.getCountry().getName());
}
测试结果:
必须为要注入成员属性设置set 方法并且set方法名称与注入的bean 名称一致
2 通过名称
spring xml配置文件配置如下:
<bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName">
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByName类 和 UserDefault 类内容一致
进行测试:
测试类代码如下:
@Test
public void userByName() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByName user = (UserByName)appliction.getBean("userByName");
System.out.println("country:"+user.getCountry().getName());
}
测试结果:
注入的成员属性必须有set方法 并且set方法名称与属性名称一样
3 通过类型
spring xml配置文件配置如下:
<bean id="userByType" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByType" autowire="byType"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByType 和 UserDefault 类内容一致
进行测试:
测试类代码如下:
@Test
public void userByType() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByType user = (UserByType)appliction.getBean("userByType");
System.out.println("country:"+user.getCountry().getName());
}
测试结果:
必须有set方法 但是set方法名称可以与属性名称不同
4 通过构造器
spring xml配置文件配置如下:
<bean id="userByConstructor" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="constructor"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
UserByConstructor 具体代码如下:
public class UserByConstructor {
private Country country;
public UserByConstructor(Country country) {
super();
this.country = country;
}
public Country getCountry() {
return country;
}
}
进行测试:
测试类代码如下:
@Test
public void userByConstructor() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserByConstructor user = (UserByConstructor)appliction.getBean("userByConstructor");
System.out.println("country:"+user.getCountry().getName());
}
测试结果:
constructor 的方式无需提供set方法
@Resource和@Autowired区别
- @Resource 通过 byName 方式自动装配
- @Autowired 通过ByType 方式自动装配
- @Autowired 和@Qualifier 可以实现ByName的效果
如果Spring中有2个类型相同的Bean在通过@Autowired会报错 我们可以通过@Qualifier 标签来进行区分。
需要注意的是@Resource是javax.annotation包下的注解类 通过注解注入无需提供set方法
注解注入实战演示
1 @Resource
首先要创建我们演示的基础类:
ICountry接口类 方便创建多个Bean操作演示用
package cn.zhuoqianmingyue.ioc.di.autowire;
public interface ICountry {
String getName();
}
CountryResource 类和CountryResource2 类都实现ICountry 表示同一类型的Bean
package cn.zhuoqianmingyue.ioc.di.autowire;
import org.springframework.stereotype.Component;
@Component
public class CountryResource implements ICountry{
private String name="CountryResource";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package cn.zhuoqianmingyue.ioc.di.autowire;
import org.springframework.stereotype.Component;
@Component
public class CountryResource2 implements ICountry{
@Override
public String getName() {
return "CountryResource2";
}
}
用户类 用于依赖CountryResource 类和CountryResource2 类
package cn.zhuoqianmingyue.ioc.di.autowire;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component("userResource")
public class UserResource{
@Resource(name="countryResource2")
private ICountry countryResource;
public ICountry getCountryResource() {
return countryResource;
}
}
测试类:
@Test
public void userResource() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserResource user = (UserResource)appliction.getBean("userResource");
System.out.println("country:"+user.getCountryResource().getName());
}
测试结果:
根据上面案例结果是:没有配置Bean的名称会根据类名来进行自动装配
如果我们在@Component 标签指定名称 代码如下:
@Component("c1")
public class CountryResource implements ICountry{}
@Component("c2")
public class CountryResource2 implements ICountry{}
@Component("userResource")
public class UserResource{
@Resource(name="c1")
private ICountry countryResource;
}
测试结果:
指定Bean的名称 将按照指定名称进行自动装配
如果将name改成c3 我们没有配置任何名称为c3 的Bean
@Component("userResource")
public class UserResource{
@Resource(name="c3")
}
会报如下错误:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘c3’
如果Bean名称相同如下面代码示例:
@Component("c2")
public class CountryResource implements ICountry{}
@Component("c2")
public class CountryResource2 implements ICountry{}
会报如下错误:
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [ioc-di-autowire.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘c2’
2 @Autowired
创建CountryResource3 这里我们不实现ICountry接口
@Component
public class CountryResource3 {
public String getName() {
return "CountryResource3";
}
}
创建名称为UserAutowired的Bean 然后注入 CountryResource3
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
public CountryResource3 getCountryResource3() {
return countryResource3;
}
}
测试类代码:
@Test
public void userAutowired() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserAutowired user = (UserAutowired)appliction.getBean("userAutowired");
System.out.println("country:"+user.getCountryResource3().getName());
}
测试结果:
我们将ICountry 接口注入UserAutowired Bean中
具体代码如下:
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
@Autowired
private ICountry countryResource;
public ICountry getCountryResource() {
return countryResource;
}
public CountryResource3 getCountryResource3() {
return countryResource3;
}
}
会报如下错误:
1WARN t.support.ClassPathXmlApplicationContext: 554 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userAutowired’: Unsatisfied dependency expressed through field ‘countryResource’; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘cn.zhuoqianmingyue.ioc.di.autowire.ICountry’ available: expected single matching bean but found 2: c1,c2
这是我们需要通过@Qualifier标签来指定注入c1 还是c2
具体代码如下:
@Component("userAutowired")
public class UserAutowired {
@Autowired
private CountryResource3 countryResource3;
@Autowired
@Qualifier("c1")
private ICountry countryResource;
}
测试代码:
@Test
public void userAutowired() {
ApplicationContext appliction = new ClassPathXmlApplicationContext("ioc-di-autowire.xml");
UserAutowired user = (UserAutowired)appliction.getBean("userAutowired");
System.out.println("country:"+user.getCountryResource3().getName());
System.out.println("country:"+user.getCountryResource().getName());
}
测试结果:
Spring xml配置文件ioc-di-autowire.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<context:component-scan base-package="cn.zhuoqianmingyue"></context:component-scan>
<!-- default -->
<!--<bean id="userDefault" class="cn.zhuoqianmingyue.ioc.di.autowire.UserDefault" autowire="default">
<property name="country" ref="country"></property>
</bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>-->
<!-- byName -->
<!-- <bean id="userByName" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByName" autowire="byName"></bean>
<bean id="country" class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>-->
<!-- byType -->
<!-- <bean id="userByType" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByType" autowire="byType"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean> -->
<!-- byConstructor -->
<bean id="userByConstructor" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="constructor"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
<!-- 这种方式spring3.0就废除掉了 -->
<!--
<bean id="userByAutodetect" class="cn.zhuoqianmingyue.ioc.di.autowire.UserByConstructor" autowire="autodetect"></bean>
<bean class="cn.zhuoqianmingyue.ioc.di.autowire.Country"></bean>
-->
</beans>