慢慢来比较快,虚心学技术
1、什么是条件化Bean
在第一节中说到的profile限定了特殊环境下的Bean装载,但是有时候只根据环境进行Bean装配的选择并不一定能满足我们的需求,所以Spring4提供了更加细化的条件话配置Bean,用于对特定条件才可以进行装配的Bean进行配置
2、怎么条件化配置Bean
条件化配置Bean主要依赖于一个注解和一个接口:
@Conditional(MathIsProd.class)---条件判断注解
Condition接口-----------------------------@Conditional中的条件类必须实现的接口,提供了match方法,进行条件逻辑的编写
系统进行Bean装配时,遇到@Conditional会先对其所包含的条件类执行match方法,如果方法返回为true,则对该bean进行装配,如果方法返回为false,则不对该bean进行装配
简单实现:利用@Conditional间接实现@Profile("prod")功能
//基本类
@Component
public class BaseBean {
private String name="BaseBean";
public void setName(String name){
this.name = name;
}
}
//接口
public interface BaseService {
void update();
}
//接口实现类1
@Component
public class BaseServiceImpl1 implements BaseService {
@Autowired
private BaseBean baseBean;
@Override
public void update() {
System.out.println("BaseServiceImpl1 "+baseBean.getName());
}
}
//接口实现类2
@Component
public class BaseServiceImpl2 implements BaseService {
@Autowired
private BaseBean baseBean;
@Override
public void update() {
System.out.println("BaseServiceImpl2 "+baseBean.getName());
}
}
//测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = {ComponentConfig.class})
public class AppComponentTest {
@Autowired
private ApplicationContext applicationContext;
//注入baseService
@Autowired
private BaseService baseService;
@Test
public void testPrimary(){
baseService.update();
}
}
//测试结果:注入失败,BaseService不止有一个实现类
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.my.spring.service.BaseService' available:
expected single matching bean but found 2: baseServiceImpl1,baseServiceImpl2
代码1.8中的match方法参数
AnnotatedTypeMetadata:封装了使用@Conditional注解的类的信息
ConditionContext:封装了系统环境信息以及BeanFactory等各种实现,可以用来作为条件信息的判断
其中ConditionContext有以下常用方法:
- getRegistry() --------------返回BeanDefinitionRegistry,用于 检查 bean 定义;
- getBeanFactory()---------返回ConfigurableListableBeanFactory ,用于检查 bean 是否存在,甚至探查 bean 的属性;
- getEnvironment() --------返回Environment,用于 检查环境变量是否存在以及它的值是什么;
- getResourceLoader() ---返回ResourceLoader 所加载的资源;
- getClassLoader() ---------返回ClassLoader 加载并检查类是否存在。
注:实际上@Profile同样注解使用了@Conditional注解,且使用ProfileCondition.class作为其条件判断类,源码如下,有兴趣自行查看:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
/**
* The set of profiles for which the annotated component should be registered.
*/
String[] value();
}