细说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的实现类,这些类大多是给组件做了某种增强。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,713评论 2 22
  • 本来是准备看一看Spring源码的。然后在知乎上看到来一个帖子,说有一群**自己连Spring官方文档都没有完全读...
    此鱼不得水阅读 6,934评论 4 21
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,652评论 18 139
  • (二)我遇到你的时间迟到了 5. 成长 日子轻轻浅浅的走着,似乎不着痕迹,豆蔻年华的我们,也似乎不懂得时间的...
    慵懒的小虫子阅读 347评论 0 2
  • 前半部分我一度想放弃不看了,前半部分描述的就是久木和凛子两人的婚外情约会,和两人的内心的变化。而两人之间的情色描述...
    张_凯阅读 4,687评论 0 1