细说Spring——IoC详解(@Conditional注解和生命周期)

一、前言

最近发现自己太丧了,因为是考试周,但是感觉考试及格就好,所以也无心复习,又因为马上要放暑假了,归心似箭啊,感觉有点厌学。这几天都在看《士兵突击》,挺励志的一个电视剧,感觉还是不能就这样丧下去,希望接下来的几天加油吧。

二、@Conditional

@Conditional注解的作用是:按照一定的条件进行判断,满足条件后才在中容器中注入该组件。这个注解在SpringBoot的底层实现中大量的使用,学习一下有助于将来学习SpringBoot,我们先来看一下配置类:

@Configuration
public class MainConfig2 {
    @Conditional({WindowsCondition.class})
    @Bean("windows")
    public Person person01() {

        return new Person("windows", 22);
    }

    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public Person person02() {

        return new Person("linux", 26);
    }
}

我用@Conditional注解标注了两个方法,这两个方法都是向容器中注入组件的方法,我们看一下@Conditional注解中的参数:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();

}

我们可以看到参数是Condition的子类,上面已经实现了两个,分别是:
WindowsCondition

public class WindowsCondition implements Condition {
    /**
     *
     * @param context   判断条件能使用的上下文环境
     * @param metadata   注解信息
     * @return
     */
    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");
        if(property.contains("Windows")) {
            return true;
        }
        return false;
    }
}

LinuxCondition

public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //3、获取当前的运行时环境,不如当前的操作系统
        Environment environment = context.getEnvironment();

        String property = environment.getProperty("os.name");
        if(property.contains("linux")) {
            return true;
        }
        return false;
    }
}

这两个类是判断当前的操作系统的,综合配置类来看,就是如果当前操作系统为windows,就把名字为“windows”的组件放入容器,如果是linux系统,就把名字为“linux”的组件放入容器。然后我们就来看一下测试的结果吧:
这里写图片描述
我们可以看到容器中有windows组件,我们也可以同过虚拟机参数:-Dos.name=linux来测试一下linux的情况。这里只是简单的@Conditional注解的用法,这个注解也可以作用与类上,说明只有满足条件,这个类中的所有的组件注册才能生效,在SpringBoot的自动配置类中大量的使用了这个注解,有兴趣的可以自己研究一下。

三、生命周期

组件的生命周期是指:组件的创建,组件初始化,组件的销毁。
这里组件的销毁仅指在容器中单例的的组件,如果是多例的组件那么销毁和容器是没有关系的。
我在 细说Spring——IoC详解(Bean的生命周期中讲解过组件的生命周期,我们可以在XML中指定init-method和destory-method的方法来控制组件的生命周期,我们现在来学习一下使用注解的方法怎么控制组件的生命周期。
1、我们先来看第一种方法:
组件Car类

@Component
public class Car {
    public Car() {
        System.out.println("car constructor.....");
    }

    public void init() {
        System.out.println("car init......");
    }

    public void destory() {
        System.out.println("car destory......");
    }
}

配置类:

@Configuration
@ComponentScan("com.jiayifan.bean")
//@Import(value = Cat.class)
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destory")
    public Car car() {
        return new Car();
    }

}

我们可以在组件类中写一个初始化方法和销毁方法,然后在配置类中使用@BeaninitMethoddestroyMethod来指定相应的方法。
然后我们测试一下:

public class IOCTest_lifeCycle {

    @Test
    public void test01() {
        //1、创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成");
        //关闭容器
        applicationContext.close();

    }
}

这里写图片描述
我们可以看到先调用了Car的构造器,然后调用了Car的初始化方法,最后在容器关闭前调用了Car的销毁方法。
2、通过让组件实现InitializingBean接口实现初始化,通过实现DisposableBean接口实现销毁
组件Cat类

@Component
public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
        System.out.println("cat constructor.....");
    }

    //销毁方法
    public void destroy() throws Exception {
        System.out.println("cat destory......");
    }

    //初始化方法
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat afterPropertiesSet......");
    }
}

配置类不变,测试类不变,看一下测试结果:
这里写图片描述

3、可以使用JSR250中定义的两个注解:@PostConstruct 实现初始化、@PreDestroy 实现销毁
组件Dog类

public class Dog {
    public Dog() {
        System.out.println("dog constructor.....");
    }

    //在Construct之后执行
    @PostConstruct
    public void init() {
        System.out.println("dog @PostConstruct .......");
    }

    //在destory执行之前
    @PreDestroy
    private void destoyr() {
        System.out.println("dog @PreDestroy.......");
    }
}

配置类和测试类不变,测试结果:
这里写图片描述

4、BeanPostProcessor接口
还记得我在:细说Spring——IoC详解(深入IoC实现)中说过的BeanPostProcessor吗,其实它也可以用来控制生命周期。不过这个接口并只涉及到组件初始化,我们可以通过实现这个接口来在组件初始化前对组件做一些增强,下面我们来看一下怎么使用:
组件MyBeanPostProcessor类

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization...." + beanName + "=>" + bean);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization...." + beanName + "=>" + bean);
        return bean;
    }
}

在所有组件的初始化前后进行一些处理工作,包含两个方法:

  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之后工作

配置类不变
测试类:

public class IOCTest_lifeCycle {

    @Test
    public void test01() {
        //1、创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成");
        printBeans();
        //关闭容器
        applicationContext.close();

    }
    private void printBeans() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }
}

测试结果:
这里写图片描述

我们可以看到,我们的Car组件在初始化前调用了我们的MyBeanPostProcessor中的postProcessBeforeInitialization方法,在初始化后调用了postProcessAfterInitialization方法。我们可以在Spring中发现很多BeanPostProcessor的实现类,这些类大多是给组件做了某种增强。

猜你喜欢

转载自blog.csdn.net/q982151756/article/details/80786268