Spring实战——高级装配

2019-07-14  本文已影响0人  WhyDoWeLive
@profile("场景标识名")

不同的环境中(开发环境、生产环境、QA环境)用到的bean可能不同,那么在运行时我们如何在Spring中根据环境,决定创建哪个bean和不创建哪个bean?使得同一个部署单元(war文件)能够适用于所有环境,无须重新构建

通过在JavaConfig中声明@Bean的类或函数上添加@profile("场景标识名"),此时,除非对应场景的profile处于激活状态,否则对应的@Bean不会被创建。
注意,没有指定profile的Bean始终都会被创建,与激活哪个profile没有关系。

//插曲:看一下注解是怎么定义的
@Conditional(........)
public  @interface Profile{}
@Conditional(条件)——条件化创建bean

假设你希望应用的类路径下包含特定库才创建bean;或者希望在某个特定bean也声明了之后才创建等等。

处理自动装配的歧义性

当有多个Bean满足注入条件时,Spring 会抛出异常。Spring提供了两种解决方案@Primary和@Qualifier。

...
@Qualifier
public @interface Cold{}

...
@Qualifier
public @interface Creamy{}

这样在声明@Bean和注入时,通过叠加多个如上的注解,保证满足条件的bean只有一个。

Bean的作用域

默认情况下,Spring应用上下文中所有的bean都是单例bean。
有时,有些class会保持一些状态并且是易变,因此重用是不安全的,所以不适合作为单例bean

Spring定义了多种作用域用于创建bean:

单例是默认作用域,通过@Scope(作用域类型)可更改Bean的作用域,可与@Component和@Bean一起用

会话作用域

在典型的电子商务应用中,可能会有一个bean代表用户的购物车。如果购物车是单例的话,那么将导致所有的用户都会向同一个购物车添加商品。另一方面,如果购物车是原型作用域的,那么在应用中某一个地方往购物车添加商品,在应用的另外一个地方可能就不可用了,因为在这里注入的是另外一个原型作用域的购物车。

因此,需要会话作用域:为每个会话创建一个ShoppingCart,在每个会话中bean相当于单例的。

使用方式一般为:

@Scope(
    value=WebApplicationContext.SCOPE_SESSION, 
    proxyMode=ScopedProxyMode.INTERFACES/TARGET_CLASS
)

为什么使用proxyMode?
假设有个StoreService类依赖会话作用域的ShoppingCart。
首先,直到有用户进入系统,创建了会话之后,才会出现ShoppingCart实例,因此这之前,是不存在ShoppingCart的实例的。
其次,每个用户都有一个ShoppingCart,但我们不想让Spring注入某个特定的ShoppingCart到StoreService,而是希望当StoreService处理购物车功能时,它所使用的ShoppingCart实例恰好是当前会话所对应的那一个。

解决办法:动态代理模式
向StoreService注入一个ShoppingCart的代理,当StoreService调用ShoppingCart的方法时,代理对其解析并将调用委托给会话作用域内真正的ShoppingCart Bean

proxyMode的两个可选参数分别为实现接口的JDK Proxy 代理和通过继承的CGLib代理

属性占位符、SpEL(Spring表达式语言)

可用于运行时注入值,注意不是对象,怎么做先不记录了,知道就好了。

public Person getParent()
{
    //下面两个参数时硬编码的,通过属性占位符或SpEL可运行时注入
    return new Person("wxs", "sheep");
}
上一篇 下一篇

猜你喜欢

热点阅读