1.处理自动装配的歧义性
在学习笔记一中,使用了@Autowired注解进行自动装配,当仅有一个bean匹配所需的结果时自动装配才是有效的。如果有多个结果匹配的话,这种歧义性会阻碍自动装配。
当发生歧义性的时候,Spring提供了多种可选方案来解决这样的问题:
①将某一个bean设为首选(primary)的bean
②使用限定符(qualifilter)
假设有甜点接口
public Interface Dessert{}
当你选择某一个甜点时,有不同的选择。
1.1标示首选的bean
如果将IceCream标记为首选甜点,则使用注解@Primary
@Component
@Primary
public class IceCream implements Dessert{.....}
如果使用Java配置显式地声明IceCream,那么@Bean方法应该如下所示:
@Bean
@Primary
public Dessert iceCream(){
return new IceCream();
}
使用XML配置的话,如下:
如果将多个bean设为首选,歧义性还未得到解决,那么可以使用更为强大的限定符。
1.2限定自动装配的bean
@Qualifier注解是使用限定符的主要方式。它可以与@Autowired和@Inject协同使用。比如把IceCream注入到serDessert()之中:
@Autowired
@Qualifier("iceCream")
public void serDessert(Dessert dessert){
this.dessert = dessert;
}
iceCream是bean的ID。
创建自定义的限定符:
@Component
@Qualifier("cold")
public class IceCream implements Dessert{...}
2.bean的作用域
在默认情况下,Spring应用上下文的bean都是单例的。在Spring中定义了多个作用域以应对不同应用场景。
①单例(Singleton):在整个应用中,只创建一个实例。
②原型(Prototype):每次注入或者通过Spring应用上下文获取的时候都会创建一个新的实例。
③会话(Session):在Web应用中为每个会话创建一个实例。
④请求(Request):在Web应用中,为每一个请求创建一个实例。
如果要为某一个类选择作用域可以使用@Scope注解。
如:
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad{......}
ConfigurableBeanFactory.SCOPE_PROTOTYPE的值是prototype,也可以使用@Scope("prototype")
如果在Java配置中显式配置可以如下配置:
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad notepad (){
return new Notepad ();
}
在XML中配置可以是:
3.使用会话和请求作用域
在电子商务应用中购物车bean,会话作用域最为合适。
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERDACES)
public ShoppingCart cart(){....}
假设需要将ShoppingCart
注入到单例的StoreService bean的setter方法中
@Component
public class StoreService {
@Autowired
public void setShoppingCart ( ShoppingCart cart){
this.shoppingCart = cart;
}
}
因为StoreService 是单例的,在Spring创建它的bean的时候,ShoppingCart 的bean还没有创建。另外,系统中会有多个ShoppingCart 实例:每个用户一个。我们不想让Spring注入某个固定的ShoppingCart 实例到StoreService 中,我们希望的是StoreService 处理购物车时,所使用的购物车实例恰好是当前会话的那一个。Spring并不会将实际的购物车的bean注入到StoreService中,Spring 会注入一个到购物车bean的代理中。这个代理会暴露与购物车相同的方法,所以StoreService就会认为它就是一个购物车,但是当StoreService调用ShoppingCart的方法时代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart bean。
proxyMode=ScopedProxyMode.INTERDACES就表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。如果ShoppingCart不是接口而是类的话就需要将proxyMode的值设置为ScopedProxyMode.TARGET_CLASS。
在XML中声明会话作用域代理,需要使用Spring aop命名空间:
上面是默认使用CGLIb代理。如果要求使用的是基于接口代理可以设置
(此同 proxyMode=ScopedProxyMode.INTERDACES)