Spring自動裝配(autowire)篇

什麼是自動裝配

自動裝配幫我們省去了 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>
  1. byName
    通過名稱進行自動裝配。
    配置方式如下:
    <bean autowire="byName"></bean>
  1. byType
    通過注入Bean的類類型來進行匹配。
    配置方式如下:
   <bean autowire="byType"></bean>
  1. 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區別

  1. @Resource 通過 byName 方式自動裝配
  2. @Autowired 通過ByType 方式自動裝配
  3. @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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章