1. 根据条件自动选择环境创建合适的 Bean
-
@Profile 根据环境装配
利用注解 @Profile(“dev”),可以在类上面和方法上
怎么激活,利用spring.profiles.active 和 spring.profiles.default 设置环境变量或者 作为DispatcherServlet的初始化参数
在测试时可以利用@ActiveProfiles(“dev”) -
@Conditional 根据条件注解
这个特别牛逼,可以在只有应用的类路径下有特定的类或者只有当另外某个Bean存在时才会创建。
这俩个注解在 spingboot 中有大量应用 。
- 具体应用
@Bean
@Contidional(MagicExistCondition.class)
public majicBean majicBean(){
return MagicBean();
}
// 作为条件的MagicExistCondition 必须实现 Condition 接口
public class MagicExistCondition implements Condition{
public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata){
Enviorment env = context.getEvironment();
return env.containsProperty("magic")
}
}
2. 处理自动装配的歧义性
-
如果我们使用 @Autowire 注解时,注入的Bean 类型 有两个以上的实现类就会抛出异常,指示没有唯一的bean被发现
我们可以使用三种方式解决这个问题 -
第一,标识首选的Bean ,使用@Primary ,如果有三个实现类,在其中一个标识这个注解,spring就会使用它,但是如果在其中两个标识了,也会报错,
@Component
@Primary
public class IceCream implements Dessert{
}
@AutoWired
public void setDessert(Dessert dessert){
this.dessert=dessert;
}
- 第二,使用@ Qualifier ,我们可以给Bean实现类添加这个注解,标识bean的id,然后配合@Autowire使用,如果两个以上有同样的cold,也会出问题,如果你想一个Bean上定义两个@Qualifier 不被java允许的
@Component
@Qualifier("cold")
public class IceCream implements Dessert{
}
@AutoWired
@Qualifier("cold")
public void setDessert(Dessert dessert){
this.dessert = dessert;
}
- 第三,使用自定义的限定符注解,我们可以自己定义一个,解决不能定义俩个的问题
// 实现自定义注解
@Target(ElementType.CONSTRUCTOR,ElementType.FIFLD,
ElementType.METHOD,ElementType.Type)
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold{
}
@Target(ElementType.CONSTRUCTOR,ElementType.FIFLD,
ElementType.METHOD,ElementType.Type)
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy{
}
// 使用两个bean标识符
@Component
@Cold
@Creamy
public class IceCream implements Dessert{
}
//使用两个自定义注解解决java不允许两个@Qualifer问题
@AutoWired
@Cold
@Creamy
public void setDessert(Dessert dessert){
this.dessert = dessert;
}
3. bean 的作用域
- 单例: 适合无状态的bean
- 原型: 适合有状态的bean 每次都会创建一个bean
@Component
@Scope("prototype")
public class Notepad{
}
- 请求 request
- 会话session,例如购物车,每个用户会话都有一个往里面添加商品,
@Component
@Scope(WebApplicaitonContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode=INTERFACES)
public Shopping cart(){
}
//注意这里商店 StoreServie是单例的,Shopping是会话,这是还不存在,注入回报错,为了解决这个问题
// 所以需要使用 proxyMode spring会注入一个Shopping的代理,当真正调用时才会进行懒解析,将其委托给
//会话作用域的真正的Shopping
@Componemt
public class StoreService{
@Autowired
public void setShopping(Shopping shopping){
this.shopping=shopping;
}
}