网站首页 > 技术文章 正文
写在前面
今天面试了几个人,我都有意问到javaConfig这个概念,熟悉的朋友应该知道这个隶属于SpringBoot体系里。但是最后几个人回答的都不尽如人意。趁此,我们一起来看下这个东西怎么理解。
一般同学听到这个肯定会懵逼掉,不太理解这个词的究竟面试官想要考什么,其实目的就是考察Spring的注解,如何注册成bean,也就是从SpringBoot作为切入点回答。
提前备注下:
传统spring一般都是基于xml配置的,不过后来新增了许多JavaConfig的注解。特别是springboot,基本都是清一色的java config
注解
耳熟能详的第一个可能就是@RestController
spring4为了更方便的支持restfull应用的开发,新增了RestController的注解,比Controller注解多的功能就是给底下的RequestMapping方法默认都加上ResponseBody注解,省得自己再去每个去添加该注解。
这就是java Config的概念所应用。
接着再说@Configuration
使用@Configuration 声明配置类时有两种方法来生成bean
- 方法一:在配置类中定义一个方法,并使用 @Bean 注解声明
- 方法二:在类上使用 @Component注解,并在配置类上声明 @ComponentScan("类的路径"),这样会自动扫描 @Component并生成bean
以上两种方法可能在SpringBoot开发当中应用的比较多,我们看个例子
第一种方法:
// 这个会交由Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration 代表这是一个配置类,相当于applicationContext.xml
@Configuration
public class TestConfig {
//注册一个bean,就相当于 bean标签
//方法名,相当于bean标签中的id属性
//方法返回值,相当于bean标签的class属性
@Bean
public User getUser() {
return new User();//返回要注入的bean对象
}
}
第二种
// 这个会由Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration 代表这是一个配置类,相当于applicationContext.xml
@Configuration
@Component("com.pojo")
//将其他配置文件融合到当前的类中
@Import(com.config.TestConfig.class)
public class TestConfig {
public User getUser() {
return new User();
}
}
public class User {
private String name;
public String getName() {
return name;
}
@Value("苏世")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
'}';
}
}
public class Test {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
User user = (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
这就是一个最基本的案例,实现起来非常的简单。下面我们着重分析一下注解的作用,为什么能实现类似于Spring中XML文件一样的作用。
分析源码
想要了解为什么@Configuration会有这样的作用,我们可以跟进去这个注解看看。
进去之后我们会发现,这个注解标签是一个元注解,由很多其他的注解实现,有一个我们应该很熟悉,那就是@Component,有着了这个注解就可以被@ComponentScan扫描并处理。Spring5.0已经自动扫描了,不需要我们自己再去添加了。
首先是@AliasFor标签:
在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。
然后是value() :
意思是默认的值就是空,此时我们就可以指定@Configuration(value="属性值")的这种方式,因为只有一个value所以value可以省去不写。
最后是proxyBeanMethods:
有了 proxyBeanMethods 属性后,配置类不会被代理了。主要是为了提高性能,如果你的 @Bean 方法之间没有调用关系的话可以把 proxyBeanMethods 设置为 false。否则,方法内部引用的类生产的类和 Spring 容器中类是两个类。
运行角度分析
看到这里,可能就要深入到Spring的源码中看了。Spring容器启动时,ApplicationContext接口的实现类AnnotationConfigApplicationContext会执行refresh方法,往BeanFactory注册bean就在此方法完成。我们看到这个refresh是核心。我们进入到这个源码中看看:
我截取了其中一部分的源码,在里面有一个方法很关键,那就是invokeBeanFactoryPostProcessors,意思是我们Spring容器首先会初始化BeanFactory,然后激活各种beanFactory处理器,也就是执行invokeBeanFactoryPostProcessors,我们看看这个方法:
在这个方法的内部的核心是ConfigurationClassPostProcessor,这个方法看到@Configuration,就会开启类的加载,这里也就是bean的加载。剩下的越挖越深,源码也越来越深。大体步骤我们可以总结一下:
总结
ConfigurationClassPostProcessor处理器解析@configuration配置类主要过程:
(1)Spring容器初始化时注册ConfigurationClassPostProcessor
(2)Spring容器初始化执行refresh()方法中调用ConfigurationClassPostProcessor
(3)ConfigurationClassPostProcessor处理器借助ConfigurationClassParser完成配置类解析
(4)ConfigurationClassParser配置内解析过程中完成嵌套的MemberClass、@PropertySource注解、@ComponentScan注解(扫描package下的所有Class并进行迭代解析,主要是@Component组件解析及注册)、@ImportResource、@Bean等处理
(5)接下来完成@Bean注册, @ImportResource指定bean的注册以及@Import的bean注册
(6)有@Bean注解的方法在解析的时候作为ConfigurationClass的一个属性,最后还是会转换成BeanDefinition进行处理, 而实例化的时候会作为一个工厂方法进行Bean的创建
现在大致应该明白了,其实一句话说完,还是想办法识别注解,完成和XML一样的功能。
弦外之音
其实这个知识点,大家在学习SpringBoot的自动配置注解那块是一样的。
- 上一篇: Linux系统网络相关的常用命令集合
- 下一篇: 实力解剖一枚挖矿脚本,风骚操作亮瞎双眼
猜你喜欢
- 2024-10-25 号外号外:网关是什么意思?网关的作用是什么?
- 2024-10-25 MIUI里面的原声安卓功能详解(miui 原生安卓)
- 2024-10-25 恕我直言,牛逼哄哄的MongoDB你可能只会30%
- 2024-10-25 网络基本概念和测试(网络的基础知识)
- 2024-10-25 过程控制系统PCS 7 简要概述和视图
- 2024-10-25 一小时开发钉钉工作台自定义组件(钉钉怎么自定义设置工作台)
- 2024-10-25 Config 2022 落幕!这15项新功能让 Figma 更简单好用了
- 2024-10-25 路由器WPS功能有什么用?家里买路由器必须要这个功能吗
- 2024-10-25 一个注解搞定责任链,学还是不学?
- 2024-10-25 系统小技巧:有备无患 Windows 10注册表自动备份/还原
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)