4.@Conditional
按照一定的条件进行判断,满足条件给容器中注册bean;
例:
如果系统是windows,给容器中注册(“bill”)
如果是linux系统,给容器中注册(“linus”)
创建LinuxCondition,WindowsCondition并实现Condition接口.
LinuxCondition
//判断是否是Linux系统 public class LinuxCondition implements Condition { /** * * @param context 判断条件使用的上下文(环境) * @param metadata :注释信息 * @return */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //1.获取IOC使用的BeanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //2.获取类加载器 ClassLoader classLoader = context.getClassLoader(); //3.获取当前环境信息 Environment environment = context.getEnvironment(); //4.获取Bean定义的注册类 BeanDefinitionRegistry registry = context.getRegistry(); String property = environment.getProperty("os.name"); //可以判断容器中的Bean注册情况,也可以给容器中注册Bean if(property.contains("linux")){ return true; } return false; } }
WindowsCondition
//判断是否是windows系统 public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")){ return true; } return false; } }
MainConfig
//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效; //@Conditional({WindowsCondition.class}) @Configuration public class MainConfig3 { /** * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean * * 如果系统是windows,给容器中注册("bill") * 如果是linux系统,给容器中注册("linus") */ @Conditional({WindowsCondition.class}) @Bean("bill") public Person person01(){ return new Person("Bill Gates",62); } @Conditional({LinuxCondition.class}) @Bean("linus") public Person person02(){ return new Person("linus",48); } }
测试:
@Test public void test05() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class); String[] names = applicationContext.getBeanNamesForType(Person.class); //获取系统环境配置对象 ConfigurableEnvironment environment = applicationContext.getEnvironment(); //动态获取环境变量 String property = environment.getProperty("os.name"); System.out.println(property); for (String name : names) { System.out.println(name); } Map <String, Person> persons = applicationContext.getBeansOfType(Person.class); System.out.println(persons); }
运行结果:
当在类上使用时表示:
对类中组件统一设置,满足当前条件,这个类中配置的所有bean注册才能生效;
5.@Import
5.1 @Import(要导入的容器中的组件);
容器中会自动注册这个组件,id默认是全类名.
创建Color,Red类作为导入的组件.
MainConfig
//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效; @Conditional({WindowsCondition.class}) @Configuration //@Import(value = Color.class) @Import({Color.class, Red.class}) public class MainConfig4 { @Bean("person") //修改方法名称 public Person person(){ return new Person("lisi",20); } @Conditional({WindowsCondition.class}) @Bean("bill") public Person person01(){ return new Person("Bill Gates",62); } @Conditional({LinuxCondition.class}) @Bean("linus") public Person person02(){ return new Person("linus",48); } }
测试:
@Test public void test06() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig4.class); String[] names = applicationContext.getBeanDefinitionNames();//获取容器中所有的对象名称 for (String name : names) { System.out.println(name); } }
运行结果:
5.2 ImportSelector
返回需要导入的组件的全类名数组;
作用:批量注册Bean:
编写MyInportSelector 实现ImportSelector接口
public class MyInportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.rg.domain.Blue","com.rg.domain.Yellow"}; } }
MainConfig上添加注解:@Import({Color.class, Red.class, MyInportSelector.class})
运行结果:
5.3 MyImportBeanDefinitionRegistrar
手动注册bean到容器中(可以指定Bean的名称)
创建MyImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,编写注册的逻辑.
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类; * 把所有需要添加到容器中的bean;调用 * BeanDefinitionRegistry.registerBeanDefinition手工注册进来,可以指定名称. */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("com.rg.domain.Red"); boolean definition2 = registry.containsBeanDefinition("com.rg.domain.Blue"); if(definition && definition2){ //指定Bean定义信息; RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class); //注册一个Bean,指定Bean名 registry.registerBeanDefinition("rainBow",rootBeanDefinition); } } }
MainConfig上添加注解:@Import({Color.class, Red.class, MyInportSelector.class, MyImportBeanDefinitionRegistrar.class})
运行结果:
6.使用FactoryBean注册组件
使用Spring提供的 FactoryBean(工厂Bean);
1)、默认获取到的是工厂bean调用getObject创建的对象
2)、要获取工厂Bean本身,我们需要给id前面加一个& &colorFactoryBean
创建ColorFactoryBean 实现FactoryBean接口
//创建一个Spring定义的FactoryBean public class ColorFactoryBean implements FactoryBean<Color> { //返回一个Color对象,这个对象会添加到容器中 @Override public Color getObject() throws Exception { System.out.println("ColorFactoryBean...getObject..."); return new Color(); } //返回对象的类型 @Override public Class <?> getObjectType() { return Color.class; } //是否单例 //true:这个bean是单例,在容器中保存一份 //false:多例,每次获取都会创建一个新的Bean @Override public boolean isSingleton() { return false; } }
编写MainConfig
//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效; @Configuration public class MainConfig5 { // 使用Spring提供的 FactoryBean(工厂Bean); //1)、默认获取到的是工厂bean调用getObject创建的对象 //2)、要获取工厂Bean本身,我们需要给id前面加一个& &colorFactoryBean @Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); } }
进行测试:
@Test public void test07() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig5.class); //Bean 获取的是调用getObject创建的对象 Object bean = applicationContext.getBean("colorFactoryBean"); Object bean2 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean2 is Type:"+bean2.getClass()); System.out.println(bean==bean2); Object bean3 = applicationContext.getBean("&colorFactoryBean"); System.out.println(bean3.getClass()); }
运行结果:
&&小结:给容器中注册组件的四种方式
1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
2)、@Bean[导入的第三方包里面的组件]
3)、@Import[快速给容器中导入一个组件]
1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
2)、ImportSelector:返回需要导入的组件的全类名数组
4)、使用Spring提供的 FactoryBean(工厂Bean);
1)、默认获取到的是工厂bean调用getObject创建的对象
- 2)、要获取工厂Bean本身,我们需要给id前面加一个& &colorFactoryBean
7.生命周期
7.1指定初始化和销毁方法
通过@Bean指定init-method和destroy-method,相当于xml中的
<bean id="person" class="com.rg.domain.Person" init-method="XXX" destroy-method="XXX" >
构造(对象创建)
单实例:在容器启动的时候创建对象
多实例:在每次获取的时候创建对象
初始化: 对象创建完成并赋值好,调用初始化方法…
销毁:
单实例:容器关闭的时候
多实例:容器不会管理这个Bean,容器不会调用销毁方法.
编写MainConfigOfLifeCycle类
@Configuration public class MainConfigOfLifeCycle { @Scope("prototype") @Bean(initMethod="init",destroyMethod = "destroy") public Car car(){ return new Car(); } }
测试:
@Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("Container creation complete....."); applicationContext.getBean("car"); //关闭容器 applicationContext.close(); }
当是单实例时:
7.2定义初始化逻辑
通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
创建Cat类并实现InitializingBean,DisposableBean接口.
@Component public class Cat implements InitializingBean, DisposableBean { public Cat(){ System.out.println("Cat constructor..."); } @Override public void destroy() throws Exception { System.out.println("cat destroy..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("cat afterPropertiesSet ..."); } }
MainConfigOfLifeCycle配置类
@Configuration @ComponentScan("com.rg") public class MainConfigOfLifeCycle { @Bean(initMethod="init",destroyMethod = "destroy") public Car car(){ return new Car(); } }
@Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); //关闭容器 applicationContext.close(); }
运行结果:
7.3可以使用JSR250
@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
创建Dog类:
@Component public class Dog { public Dog(){ System.out.println("Dog constructor..."); } //对象创建并赋值之后调用 @PostConstruct public void init(){ System.out.println("Dog PostConstruct..."); } //容器移除对象之前 @PreDestroy public void destroy(){ System.out.println("Dog PreDestroy..."); } }
测试: