《Spring实战》——3

环境相关

 

profile的使用

@Profile(“profile名字”)来标注某个bean属于哪个profile领域。标注于类上,代表只有在特定profile激活时,该类中的bean才会被创建,没有标注profile的类始终会被创建。可用于使用在不同环境下,比如开发过程中、QA过程中或者生产过程中。现也可标注于方法级别。

在XML中使用时,在顶部声明中添加profile=“…”。例如:

<beans

    …

    profile=“dev” >

也可在同一个XML文件中,定义多个profile,即定义多个beans,每个beans添加不同的profile属性。当实际运行时只会根据环境,选择创建一个。

如何激活profile:

设置spring.profiles.active设置想激活的profile;设置spring.profiles.default设置默认激活的profile。

1、在DispatcherServlet的初始化参数中设置

例如在web.xml中:

<!— 为Servlet设置默认profiles —>

<servlet>

    …

    <init-param>

        <param-name>spring.profiles.default</param-name>

        <param-value>dev</param-value>

    </init-param>

</servlet>

2、作为Web应用的上下文参数(Context)

例如在web.xml中:

<!— 为Context设置默认profiles —>

<context-param>

    <param-name>spring.profiles.default</param-name>

    <param-value>dev</param-value>

</context-param>

3、JNDI条目

同样在web.xml中:

<env-entry>

    <env-entry-name>spring.profiles.default</env-entry-name>

    <env-entry-type>java.lang.String</env-entry-type>

    <env-entry-value>dev</env-entry-value>

</env-entry>

4、环境变量

例如在Linux系统下,设置.bash_profile文件,将spring.profiles.default=dev添加进去。

5、JVM系统属性

可通过命令行-D<name>=<value>来设置,例如java -Dspring.profiles.default=dev。

6、在测试类中使用@ActiveProfiles注解

在测试类级别标注@ActiveProfiles(“dev”)。

 

条件化bean

为实现bean级别的条件化配置,使用标注@Conditional,只有符合条件的bean才会被创建。@Conditional(condition.class),传入的condition类需实现Condition接口,调用其中的matches()方法,通过返回的布尔值进行判断。matches方法有两个传入参数,一个是ConditionContext,一个是AnnotatedTypeMetadata。前者可以调用其中的方法获得一些环境变量,如getRegistry()检查bean定义,getBeanFactory()检查bean是否存在,getEnvironment()获得环境变量,getResourceLoader()获得加载的资源,getClassLoader()获得类加载器。后者获得标注@Conditional的bean上的其他注解。

 

解决注入的二义性

当被注入的对象存在多个匹配的bean时,无法进行正确装配,需要处理注入bean的二义性。

有两种处理方法:

一,可以在bean处进行@Primary标注,则有该注解的bean成为首选的bean,但是如果存在多个Primary注解,则二义性仍会发生。

二,在被注入的对象、方法进行@Qualifier标注,例如@Qualifier(“beanName”),则能明确该地方选择ID为beanName的bean。在bean处进行@Qualifier的标注,则可以使被标注的bean获得限定符。例如

@Component

@Qualifier(“name”)

public class BeanName {…}

表示当被注入的对象进行@Qualifier(“name”)标注时,注入的是BeanName这个对象,即使之后bean产生修改,不叫BeanName这个名字了,也可完成注入。如果同一限定符指向多个bean,需要用多个限定符来制定唯一的bean,则需避开同一标记(即@Qualifier)不能多次使用这个限定。可以创造自己的标注,使用模版

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})

@Rentention(RententionPolicy.RUNTIME)

@Qualifier

public @interface <name>{}

第一行表示该注解可作用的领域;第二行表示该注解可保留的阶段,共有三个值(SOURCE,CLASS,RUNTIME),分别表示在源码阶段(被编译时即被忽略,在class文件中不可见)、编译阶段(在class文件中可见,但被JVM忽略)、运行阶段(JVM可见,并且可被读取、使用)保留;第三行表示该注解是一个限定符。

 

bean的作用域

为什么需要规定bean的作用域?在一般情况下,注入的bean都作为一个单例,如果这个实例应用在多个场景下,一些场景要求对它属性进行修改,一些不希望它的属性发生改变,就会产生冲突。因此针对不同的bean的应用场景,需要规定不同的作用域。

一般有四种作用域:

1、单例(Singleton),最常见的场景

2、原型(Prototype),每次注入都是重新创建的实例

3、会话(Session),每个会话创建一个实例

4、请求(Request),每个请求创建一个实例

在bean上使用@Scope标注,例如@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE),不标注默认为单例。如果使用XML,则在<bean>中添加属性scope=“prototype”。

对于3和4,一个例子是购物车,如果使用单例,则每个人看到的购物车是所有人一起拥有的,即你的购物车中有其他人添加的东西;如果使用原型,则每访问一个新的页面,添加产品进购物车,之前添加的商品将会不见。这里的使用需要将@Scope注解标注于被注入对象之上,例如

@Component

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

public ShoppingCart cart() {…}

该模式只有当某个用户创建完会话后,才会进行注入,创建实例。@Scope中的value制定了作用域,proxyMode指定了代理模式,使用接口代理,如果注入的不是接口,则改为TARGET_CLASS。使用XML时,在<bean>中添加元素<aop:scoped-proxy />。

为什么要使用代理?在1和2中,不必使用代理,但在3和4中,不使用代理就会在装配过程中报错。因为对于被注入的对象,它可能是一个单例bean,因此不能将多个不同的注入的bean的实例注入到其中。原理是注入的代理会根据当前的会话或请求,将调用委托给实际的bean。这样代理对象只用存在一个,但是实际注入的bean存在多个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值