错失15K的Offer!

01 引言

前两天刷到大V视频面试现场,在直播面试的时候问到:怎么保证开发的SDK的时候,部分Bean 的实例化根据配置项实例化,没有配置就不实例化?

候选人支支吾吾半天,说到拦截器、过滤器等,就是没有条件注解,硬是逼着鱼皮自己说了。自然也就失去了这份Offer。

其实这个条件注解就是@Conditional ,它是 Spring4.0版本框架的一个核心注解,专门用于 根据条件动态注册 Bean。我们今天来了解一下这个注解。

02 案例

假设我们需要按照不同的环境初始化不同的Bean,Windows下创建Windows相关的Bean,Linux下创建Linux相关的Bean

2.1 Bean定义

Windows下的Bean

public class WindowBean {

    public WindowBean() {
        System.out.println("WindowBean 构造器执行完成");
    }
}

Linux 下的Bean

public class LinuxBean {

    public LinuxBean() {
        System.out.println("LinuxBean 构造器执行完成");
    }
}

2.2 配置

@Configuration
public class BeanConfig {

    @Bean
    public WindowBean windowBean() {
        return new WindowBean();
    }

    @Bean
    public LinuxBean linuxBean() {
        return new LinuxBean();
    }
}

[顺便推个机会]

大厂摇人,前、后端/测试机会,可以吃零食,加班有加班费,稳定性较高,薪酬待遇还不错。​

2.3 启动测试

目前我们没有做任何的关于条件注解的配置,项目启动之后会这两个Bean都会被实例化。如图:

2.4 编写条件

根据环境变量os.name匹配。

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = context.getEnvironment().getProperty("os.name");
        System.out.println("WindowsCondition osName: " + osName);
        return "win".equals(osName);
    }
}

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = context.getEnvironment().getProperty("os.name");
        System.out.println("LinuxCondition osName: " + osName);
        return "linux".equals(osName);
    }
}

2.5 修改配置

WindowBean在匹配WindowsCondition 逻辑的时候,实例化BeanLinuxBean 在匹配LinuxCondition 逻辑的时候,才会实例化。

@Configuration
public class BeanConfig {

    @Bean
    @Conditional(WindowsCondition.class)
    public WindowBean windowBean() {
        return new WindowBean();
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public LinuxBean linuxBean() {
        return new LinuxBean();
    }
}

启动命令上,增加os.name=win的配置:

2.6 验证

03 源码追踪

因为使用的是注解,我们就直接看注解的上下文,以此为入口:

org.springframework.context.annotation.AnnotationConfigApplicationContext

关键代码块:

可以看到,在shouldSkip()方法中,首先会判断类或方法上是否标注了@Conditional注解,如果没有标注@Conditional注解,则直接返回false。

此时,调用的doRegisterBean()方法根据shouldSkip()的返回,决定要不要把对应的Bean会被创建并注入到IOC容器中。

自此,条件注解的内幕也就被了。

04 扩展

其实我们在平时使用的时候,往往不会直接去用@Conditional注解,反而经常会使用其扩展的注解,如下:

——转载自作者:SimonKing

全部评论

相关推荐

昨天 12:18
Brown University Java
元戎面试体验不错,不会的问题面试官还会讲解答案和原理。一半八股不是直接提问,而是给了个场景,要自己想下是哪个方向的问题。以下八股相关的是我提炼了下问题的核心考察点。一面1h+👇:为什么喜欢技术?为什么想做后台开发而不是算法?实习内容拷打10分钟:为什么用WebSocket不用HTTP,两者区别八股文:Redis源码看过吗? SDS介绍下有用Redis哪些数据结构做项目吗?分布式锁讲下,Redis怎么实现分布式锁Redis分布式锁的key超时被删除了任务还没完成怎么解决?网络不同层,TCP/IP模型介绍DNS解析的过程DNS劫持和DNS污染了解吗?算法题:Next Permutation下一个排列二面1h+👇:数据库项目问题:隔离性怎么控制的?(类似MySQL串行化的实现)串行化两个事务对同一条记录做变更会有什么问题?持久性怎么保证的?有考虑用MVCC多版本并发控制吗?加了写锁后,读锁会被阻塞吗?如果读的时候不加读锁,会出现什么问题?有实现数据库的缓存吗?缓存变更后对一个数据的查询,在数据页上会有什么处理?(并没有实现数据库层面的缓存)LRU用在什么部分?Pager页面管理器怎么使用的?Join的left join和right join中,左右表的数据量对于连接效率的影响?八股文:CAS是一个复合的指令还是像事务的指令访问磁盘页操作系统的步骤为什么访问页不是一页一页的读,而是一次性读取多张页?用户态和内核态了解多少?零拷贝在磁盘的场景还是在网络的场景?场景题:有一个两千万长度的数组存在磁盘中且不在同一个文件,如果通过下标快速定位到目标数?答:B+树,面试官补充用卡夫卡的稀疏索引更好算法题:假设有一个100GB的乱序数字文件,用100MB的内存对数字文件进行排序。答:类似归并排序,每次读取100MB的数字排序,最后归并下写入磁盘由刚才的问题引出Merge k Sorted Lists,合并k个有序链表三面1h👇:实习项目中难点讲下大模型推理失败如何保证后端返回正确结果?单点项目如何扩展为多节点?怎么看大模型推理时显卡是算力不够还是显存不够?算法题:设计一个链表,Design Linked ListHR面1h👇:自己的职业规划相关为什么留学?国内大学生和留学生有什么不一样HR姐姐详细介绍了公司的日常工作和氛围
查看30道真题和解析
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客企业服务