使用XML配置的Spring自动装配示例
在Spring中自动装配意味着Spring容器可以通过检查ApplicationContext的内容来自动解决bean之间的协作(bean依赖关系)。
在Spring中自动装配的方法
在Spring中自动布线有三个选项。
- 我们可以选择使用传统的基于XML的配置自动装配。
- 使用@Autowired注释自动布线。请参阅使用@Autowired注解的Spring自动装配后查看示例。
- 使用JSR 330的@Inject注释进行自动检测。请参阅使用@Inject和@Named注释的Spring自动装配后的示例。
在本文中,我们将看到使用XML配置的Spring自动装配示例。
Spring自动装配模式
Spring框架中有四种自动装配模式。
否–默认情况下,使用基于XML的配置时没有自动装配。 Bean引用必须由ref元素定义。
byName –在按属性名称自动装配中,Spring查找与需要自动装配的属性同名的bean。例如,如果一个bean包含一个名为item的属性(也就是说,它具有setItem()方法),Spring将查找一个名为item的bean定义,并使用它来设置该属性。
byType –在自动装配byType中,如果容器中恰好存在一个属性类型的bean,Spring会自动为其布线。如果存在多个,则会引发致命异常。如果没有匹配的bean,则什么都不会发生(未设置该属性)。
构造函数–构造函数自动装配与byType相似,但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个bean,则将引发致命错误。
使用XML配置的Spring自动装配示例
我们将在Spring中看到自动装配的示例,其中使用XML配置了自动装配模式。在该示例中,有一个用于下订单的类称为OrderService,可以从商店进行购买。在OrderServiceImpl中,必须自动关联商店的类依赖关系。
使用byName自动装配
通过名称自动装配时,Spring容器将查找具有与XML相同的名称或者ID的bean,以自动装配。
public interface OrderService {
public void buyItems();
}
public class OrderServiceImpl implements OrderService {
private IStore store;
public void setStore(IStore store) {
this.store = store;
}
public void buyItems() {
store.doPurchase();
}
}
public interface IStore {
public void doPurchase();
}
public class RetailStore implements IStore {
public void doPurchase() {
System.out.println("Doing purchase from Retail Store");
}
}
XML配置(appContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Store bean -->
<bean id="store" class="com.theitroad.springproject.service.RetailStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" autowire="byName" />
</beans>
我们可以将以下类与main方法一起使用以读取配置并调用bean方法。
public class App {
public static void main( String[] args ){
// create context using configuration
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
OrderService order = context.getBean("orderBean", OrderServiceImpl.class);
order.buyItems();
// close the context
context.close();
}
}
输出:
16:47:38.923 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [appcontext.xml] 16:47:39.009 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'store' 16:47:39.050 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean' Doing purchase from Retail Store
使用byType自动装配
当按类型自动装配时,Spring容器会在XML配置中查找具有兼容类型的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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Store bean -->
<bean id="store" class="com.theitroad.springproject.service.RetailStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" autowire="byType" />
</beans>
通过类型自动装配时的冲突解决
当按类型自动装配时,在这种情况下,Spring容器将无法确定要自动装配哪个bean并抛出NoUniqueBeanDefinitionException。
例如,如果有两个商店的Istore类型为RetailStore和OnlineStore。
public class OnlineStore implements IStore {
public void doPurchase() {
System.out.println("Doing purchase from Online Store");
}
}
两者都在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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Store bean -->
<bean id="retailStore" class="com.theitroad.springproject.service.RetailStore" />
<!-- Store bean -->
<bean id="onlineStore" class="com.theitroad.springproject.service.OnlineStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" autowire="byType" />
</beans>
这导致NoUniqueBeanDefinitionException作为Spring容器,将IStore类型的bean自动装配。
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderBean' defined in class path resource [appcontext.xml]: Unsatisfied dependency expressed through bean property 'store'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.theitroad.springproject.service.IStore' available: expected single matching bean but found 2: retailStore,onlineStore
有两种方法可以解决由于具有相同类型的多个bean定义而引起的冲突
通过使用主要属性
通过使用限定词
使用主要解决冲突
通过使用primary属性,我们可以指示当多个bean是要自动装配到单值依赖项的候选对象时,应该为特定的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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Store bean -->
<bean id="retailStore" class="com.theitroad.springproject.service.RetailStore" primary="true"/>
<!-- Store bean -->
<bean id="onlineStore" class="com.theitroad.springproject.service.OnlineStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" autowire="byType" />
</beans>
这里的primary属性与RetailStore bean一起使用,因此在自动装配时会优先考虑此bean。
使用限定符解决冲突
Spring的Qualifier元素可更好地控制选择过程。我们可以将限定符值与特定的参数相关联,从而缩小类型匹配的范围,以便为每个参数选择特定的bean。 Qualifier旨在与自动自动装配一起使用。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!-- Store bean -->
<bean id="retailStore" class="com.theitroad.springproject.service.RetailStore">
<qualifier value="rstore"/>
</bean>
<!-- Store bean -->
<bean id="onlineStore" class="com.theitroad.springproject.service.OnlineStore">
<qualifier value="ostore"/>
</bean>
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" />
</beans>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class OrderServiceImpl implements OrderService {
@Autowired
@Qualifier("ostore")
private IStore store;
public void buyItems() {
store.doPurchase();
}
}
使用构造器自动装配
通过构造器自动装配类似于通过类型自动装配,构造函数参数的构造函数类型用于搜索具有相同类型的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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Store bean -->
<bean id="retailStore" class="com.theitroad.springproject.service.RetailStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.theitroad.springproject.service.OrderServiceImpl" autowire="constructor" />
</beans>
public class OrderServiceImpl implements OrderService {
private IStore store;
public OrderServiceImpl(IStore store){
this.store = store;
}
public void buyItems() {
store.doPurchase();
}
}
输出:
18:46:38.298 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [appcontext.xml] 18:46:38.384 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' 18:46:38.422 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean' 18:46:38.465 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'retailStore' Doing purchase from Retail Store

