高级装配

本节的主要内容是:

  • Spring profile
  • 条件化的bean声明
  • 自动装配与歧义性
  • bean的作用域
  • 运行时值注入
    本节内容,并不会全部讲的非常细,因为有的开发中,由于开发进度的限制,可能并不会采用,这里只提供一引子,起到抛砖迎玉的作用。在遇到的时候,可以参考往正确的方向实现。

一、环境与profile

开发阶段中,某些环境相关做法可能并不适合迁移到生产环境中,甚至即便迁移过去也无法正常工作。数据库配置、加密算法以及与外部系统的集成是跨环境部署时会发生变化。比如,在不同的开发环境,会使用嵌入式数据库,这时候可能就需要用到配置profile bean来解决不同环境下运行不同嵌入式数据库的问题。
可以使用@Profile注解,在Spring 3.1中,只能在类级别上使用@Profile注解。不过,从Spring 3.2开始,你也可以在方法级别上使用@Profile注解,与@Bean注解一同使用。

二、条件化的bean

假设你希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。Spring 4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。

三、处理自动装配@Autowired 的歧义性

仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。

假设我们使用@Autowired注解标注了构造函数CDPlayer 如下:

    @Autowired 
    public CDPlayer cd(ICompactDisc cd2) {
        this.cd2 = cd2;
    }

这时候有好几个类都实现了ICompactDisc接口,并将他们创建为Spring应用上下文里面的bean

@Component("myComponentName01")
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}

@Component("myComponentName02")
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}

@Component("myComponentName03")
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}

这种情况下CDPlayer 类里面的自动装配,就会抛错了。那么怎么解决呢?

  • 标示首选的bean,使用@Primary注解,@Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。xml配置文件可以在<bean>元素有一个primary属性用来指定首选的bean,boolean类型
@Component("myComponentName01")
@Primary
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}
<bean id="customerDAO" class="com.sanxin.org.jdbc.JdbcCustomerDAO" primary = "true">
        <property name="dataSource" ref="dataSource" />
</bean>

如果有两个继承类,都同时用了@Primary注解呢,这时候又会抛错了,因为程序又不知道该使用哪个了。接下来看下面的限定自动装配的bean来解决这个问题。

  • 限定自动装配的bean,@Qualifier注解是使用限定符的主要方式。它可以与@Autowired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。也可以与@Component组合使用,为bean设置自己的限定符。
@Component("myComponentName01")
@Qualifier("CompactDiscImpl01 ")
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}
    @Autowired 
    @Qualifier("CompactDiscImpl01 ")
    public CDPlayer cd(ICompactDisc cd2) {
        this.cd2 = cd2;
    }

四、bean的作用域

在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。

Spring定义了多种作用域,可以基于这些作用域创建bean,包括:

  • 单例(Singleton):在整个应用中,只创建bean的一个实例。
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

1.使用@Scope注解,它可以与@Component或@Bean一起使用。

@Component("myComponentName03")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  //ConfigurableBeanFactory.SCOPE_PROTOTYPE ="prototype"
public class CompactDiscImpl01 implements ICompactDisc{
    ...
}

也可以在xml文件中配置:

<bean id="customerDAO" class="com.sanxin.org.jdbc.JdbcCustomerDAO" primary = "true" scope="prototype" />

2.以上是使用单例或是原型作用域的方式,那么,怎么实现使用会话和请求作用域
会话和请求作用域直到某个用户进入系统,创建了会话之后,才会出现bean实例。

    @Bean("myComponentName03")
    @Scope(value = WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES) 
    public CDPlayer cd(ICompactDisc cd2) {
        this.cd2 = cd2;
    }
<bean id="customerDAO" class="com.sanxin.org.jdbc.JdbcCustomerDAO" primary = "true" scope="prototype" >
      <!-- 默认情况下,它会使用CGLib创建目标类的代理。 但是我们也可以将proxy-target-class属性设置为false,进而要求它生成基于接口的代理-->
      <aop:scoped-proxy  proxy-target-class = "false"/>
</bean>

当ICompactDisc 时一个借口时,proxyMode属性被设置成了ScopedProxyMode.INTERFACES,这表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。但如果ShoppingCart是一个具体的类的话,Spring就没有办法创建基于接口的代理了。此时,它必须使用CGLib
来生成基于类的代理。所以,如果bean类型是具体类的话,我们必须要将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。

五、运行时值注入

Spring提供了两种在运行时求值的方式:

  • Spring表达式语言(SpEL)。
  • 属性占位符(Property placeholder)。

1.先看占位符,下面一个例子,将属性文件jdbc.properties中的值读取出来,并设置到DataSource这个类当中。如下代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

import com.df.test.pojo.DataSource;
import com.df.test.service.StudentService;

@Configuration
@PropertySource("classpath:jdbc.properties")
public class StudentServiceImpl implements StudentService {
    
    @Autowired
    Environment ev;     

    @Bean
    public DataSource ds(){
        return new DataSource(ev.getProperty("url"),
                ev.getProperty("username"),ev.getProperty("password"));
    }
}

如果我们依赖于组件扫描和自动装配来创建和初始化应用组件的话,那么就没有指定占位符的配置文件或类了。在这种情况下,我们可以使用@Value注解。

    @Bean("myComponentName03")
    public CDPlayer  cd(@Value("url") url,@Value("username") username,@Value("password") password) {
        return new DataSource(url,username,password));
    }

2.Spring表达式语言(SpEL)。
SpEL拥有很多特性:

  • 使用bean的ID来引用bean;
  • 调用方法和访问对象的属性;
  • 对值进行算术、关系和逻辑运算;
  • 正则表达式匹配;
  • 集合操作。

这里就不在细细分析了,可以移步Spring表达式语言(SpEL)学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容