Spring源码深度解析,Spring源码以及组件,@Conditional 条件注册Bean,@Import 注册组件(四)(附代码示例:)

四)初始Spring源码以及常用组件

目录

)初始Spring源码以及常用组件

 一, @Conditional 注解

    4.1.1,什么叫做条件注册bean?

二, @Import注解 注册组件

    4.2.1,给容器中注册组件的方式:

三,项目 Demo地址


 

 一, @Conditional 注解

  • 条件注册bean,根据指定条件选择性地注册bean实例

    4.1.1,什么叫做条件注册bean?

        模拟以下场景: 我在当操作系统为  windows 的时候   @Bean(lison)实例, 而在linux的时候  @Bean("james")

      示例代码 4.1.1:

    @Conditional(WinCondition.class)
	@Bean("lison")
	public Person lison(){
		System.out.println("给容器中添加lison.......");
		return new Person("Lison",58);
	}
	@Conditional(LinCondition.class)
	@Bean("james")//bean在容器中的ID为james, IOC容器MAP,  map.put("id",value)
	public Person james(){
		System.out.println("给容器中添加james.......");
		return new Person("james",20);
	}

    

    @Conditional(WinCondition.class)     WinCondition.class 是我自己定义的一个过滤类,  这个需要实现 Condition  接口,

  在Spring 源码中  拿到bean 的信息,  都是 通过  BeanFactory() , 而 注册   都是通过  FactoryBean()   ,获得操作 系统 可以通过 Spring 上下文,   也可以通过    System.getProperty("os.name") ,  里面 的  参数 os.name  是定义好的

public class WinCondition implements Condition{

	
	
	/*
	*ConditionContext: 判断条件可以使用的上下文(环境)
	*AnnotatedTypeMetadata: 注解的信息
	*
	*/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO 是否为WINDOW系统
		//能获取到IOC容器正在使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		if(os_name.contains("Windows")){
			return true;
		}
		return false;
	}

}

@Conditional(LinCondition.class)

public class LinCondition implements Condition{

	
	
	/*
	*ConditionContext: 判断条件可以使用的上下文(环境)
	*AnnotatedTypeMetadata: 注解的信息
	*
	*/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO 是否为WINDOW系统
		//能获取到IOC容器正在使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		if(os_name.contains("linux")){
			return true;
		}
		return false;
	}

  进行测试,得到我们想要的结果:

 public void test01(){
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfig.class);
        System.out.println("IOC容器创建完成.........");
        //app.getBean("person");//执行获取的时候才创建并初始化bean
        String[] beanDefinitionNames = app.getBeanDefinitionNames();
		for(String name:beanDefinitionNames){
			System.out.println(name);
		}
    }

 

 

  lison 已经根据我们的条件注入bean

 

二, @Import注解 注册组件

  • 手动添加组件到Ioc容器;
  • 使用 ImportSelector 自定义返回组件
  • 使用 ImportBeanDefinitionRegistrar返回自定义组件

    4.2.1,给容器中注册组件的方式:

  •  @Bean   导入第三方的类或包的组件,比如 Person 为第三方类,需要在我们的 IOC 容器 中使用,包扫描+组件的标注注解(@ComponentScan : @Contorller  @Service  @Reponsitory @Componet ,一般是针对我们自己写的类,使用这个)
  • @Import : 快速给容器导入一个组件,注意: @Bean 有点简单,
  •  @Import (要导入到容器中的组件) 容器会自动注册这个组件,beanid为全类名,
  • ImportSelector : 是一个接口,返回需要导入到容器的组件的全类名数组
  • ImportBeanDefinitionRegistrar : 可以手动添加组件到IOC容器,所有Bean的注册可以使用BeanDefinitionRegeistry写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
  • 使用Spring提供的FactoryBean(工厂bean)进行注册

   4.2.1 示例源码: 定义   6 个类, 里面没有任何操作:见 项目源码---》 cap6

         我们使用FactoryBean(工厂bean)进行注册:   将上面我们新建的 Monkey 类  注册到  工厂bean

public class JamesFactoryBean implements FactoryBean<Monkey>{

	@Override
	public Monkey getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Monkey();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Monkey.class;
	}
	
	@Override
	public boolean isSingleton() {
		return true;
	}
}

 我们使用  ImportBeanDefinitionRegistrar  添加组件实现 ImportBeanDefinitionRegistrar  接口重写 registerBeanDefinitions

方法 , AnnotationMetadata  参数 是当前类的注解信息, BeanDefinitionRegistry   即 BeanDefinition注册类。 将 dog, cat 两个类注册到 容器中去

public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/*
	*AnnotationMetadata:当前类的注解信息
	*BeanDefinitionRegistry:BeanDefinition注册类
	*    把所有需要添加到容器中的bean加入;
	*    @Scope
	*/
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
		boolean bean2 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
		//如果Dog和Cat同时存在于我们IOC容器中,那么创建Pig类, 加入到容器
		//对于我们要注册的bean, 给bean进行封装,
		if(bean1 && bean2){
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
			registry.registerBeanDefinition("pig", beanDefinition);
		}
	}

 

@ImportSelectot 接口   返回的是一个数组, 里面可以添加多个 类, 一起注册到 容器中去,

public class JamesImportSelector implements ImportSelector{
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata){
		//返回全类名的bean
		return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
	}
}

测试: -----》 项目源码: cap6Test

@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap6MainConfig.class);
		
		System.out.println("IOC容器创建完成........");
		
		//如果返回true,说明是单例,返回false,说明是多例。。
		Object bean1 = app.getBean("&jamesFactoryBean");
		Object bean2 = app.getBean("jamesFactoryBean");//取Money
		System.out.println("bean的类型="+bean1.getClass());
		System.out.println(bean1 == bean2);
		
		String[] beanDefinitionNames = app.getBeanDefinitionNames();
		for(String name:beanDefinitionNames){
			System.out.println(name);
		}

 

 

三,项目 Demo地址

Spring源码深度解析,(附代码示例 码云地址: https://gitee.com/Crazycw/SpringCode.git

参考资料:  https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/

请看下篇: Spring源码深度解析,初始Spring源码----Bean 生命周期(五)(附代码示例:)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可乐cc呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值