关于@Profile@Conditional@Primary@Qualifier及@Scope等实现高级装配的spring注解
Posted tofucai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于@Profile@Conditional@Primary@Qualifier及@Scope等实现高级装配的spring注解相关的知识,希望对你有一定的参考价值。
1、关于@Profile注解的介绍
@Profile注解主要用在针对不同环境而条件选择的注入bean
在开发过程中由于环境的不同,我们可能在针对某些功能,需要开发不同的实现,然而在某种环境中,只能激活其中一种实现,其他的实现处于不激活的状态。这个时候我们在需要创建的bean上添加@Profile注解,如@Profile("dev"),"dev"是激活的标识。当此没有注解被激活时,该注解下的所有@Bean都会被忽略掉,激活则相反。@Profile注解在spring3.1只能在类级别上注解,spring3.2开始可以在方法级别注解。
如:
@Profile("dev") public class TestProfile{ @Bean public TofuCai setTofuCai(){ return new TofuCai; } }
@profile的激活依赖两个独立的属性:spring.profiles.active和spring.profiles.default。
有多种方式来设置这两个属性
作为DispatcherServlet的初始化参数;
作为Web应用的上下文参数;
作为JNDI的条目;
作为环境变量;
作为JVM的系统属性;
在集成车市类上,使用@ActiveProfiles注解设置
如为上下文设置默认的profile:
<context-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </context-param>
注意:可以同时激活多个profile,通过逗号分隔来实现
2、@Conditional条件化的bean
当我们需要将某个bean注入到Spring中时,需要考虑到,这个bean只有在满足某些条件才去创建时,这个时候我们在这个bean的类或法返回对象的方法上,添加@Conditional注解。
例如:
@Bean @Conditional(TofuCaiCondition.class) public TofuCai tofuCaiBean(){ return new TofuCai(); }
我们在创建TofuCai这个Bean时,添加了创建的条件。
再添加这个注解后,我们需要实现Condition这个接口,只需提供matches的实现就好。
例如:
public class TofuCaiCondition implements Condition{ public boolean matches( ConditionContext context, AnnotatedTypeMetadata metadata){ Environment env = context.getEnvironment(); return env.containsProperty("tofu"); } }
其实@Profile的内部实现,也是使用了@Conditional这个注解
如下是spring 4中 @Profile的实现:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional(ProfileCondition.class) public @interface Profilr{ String[] value(); }
3、@Qualifier 处理装配的歧义性
先解释下何为歧义性:当使用@Autowired或者其他注解(如:@Inject)进行装配的时候,由于该引用下存在多个实现,spring不知晓从众多实现中取其中的哪一个进行装配。这我们称之为歧义性。而@Qualifier则能很好解决装配的歧义性。
在这之前我先说下@Primary这个注解。
当我们在某个需要注入的bean使用这个注解的时候,当发生歧义性的时候,spring就会装配有@Primary这个实现。需要注意的是,在多个实现中,只能最多只有一个实现可以使用这个注解,否则还是会产生歧义性。
这个时候,就轮到@Qualifier这个注解大显身手了。
在装配的额外增加@Qualifier("tofu")这个注解,就意味着spring会直接寻找Tofu这个bean。当然你可以在注入这个bean指定下ID,同样加上@Qualifier这个注解。例如:
@Component @Qualifier("cai") public class Tofu implement TofuCai{ }
注意:@Qualifier注解可以跟注入bean的注解一起使用,比如@Bean也是可以结合使用的,注意其不同组合之间的含义。在与注入bean的相关注解使用时,是代表限定符的意思,在装配的时候某种角度来说,是引用的指向的意思。
@Autowired @Qualifier("cai") public void setTofuCai(TofuCai tofuCai){ this.tofuCai = tofuCai; }
其实介绍到现在基本上已经很难再存在歧义性的问题了,但是有时候吧,有的人在注入bean的时候,限定符重复使用。这就导致在装配时,又出现歧义性。而且Java是不允许同一个条目上重复出现相同的注解。因此spring提供终极解决方案,即使用自定义的限定符注解,就是用户自己定义限定符注解,既可单个使用,也可组合使用。
例如:
@Target({ElementType.CONSTRUCTOR,ElementType.FILED, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Cai{}
@Target({ElementType.CONSTRUCTOR,ElementType.FILED, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Tofu{}
就分别定义了@Tofu和@Cai两个注解,直接在装配和注入的时候使用这两个注解就好了,而且既可以单独使用,也可以组合使用,不必考虑注解的重复。
4、@Scope注解——bean的作用域
先大致介绍下spring定义的一些作用域:
单例(Singleton):在整个应用中,只创建bean的一个实例。
原型(Prototype):每次注入或者通过spring应用上下文获取的时候,都会创建一个新的bean的实例。
会话(Session):在Web应用中,为每个会话创建一个bean的实例。
请求(Request):在Web应用中,为每个请求创建一个bean的实例。
在bean的类上使用@Scope注解,例如:
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class TofuCai{...}
这里就将这TofuCai设置成原型作用域。
也可以这么使用@Scope("prototype"),但是没有使用SCOPE_PROTOTYPR更加安全,不易出错。
以上是关于关于@Profile@Conditional@Primary@Qualifier及@Scope等实现高级装配的spring注解的主要内容,如果未能解决你的问题,请参考以下文章