端午特别篇(二)-Spring源码解读
警告:今天的内容可能会使您感到不适!!!
前景引入:
从线下课开始到现在,常常会听到老师说一句话,Ctrl点击去一下。一般我们会得到一个我们自己写的方法。但是,如果点的是环境提供(JDK)的方法呢,再点进去之后是啥样呢(debug时也会遇见),在文件的导航栏看到的是一个.class的文件,下面是一段java代码。到这里很多同学的Eclipse就查看不到了。于是问老师,老师这边呢,给出了一个这样的说法:我的Eclipse带反编译,你需要反编译环境才可以看到。
最近在讲到Spring时也会提到,这是底层实现的,有兴趣的同学可以去看下。
到这里,引入了两个关键词,反编译,底层。那么这到底是什么东西呢?对于我们以后的发展,及对问题的解决是否会提供思路呢?答案是肯定的。
一.源代码与反编译
1.1 源代码
在我们学习Java前,还学过C语言,更底层一点是汇编语言,最后是0101这些二进制。
通过OD对Tim进行反编译,主要内容为汇编语言
其实Java就是一部分汇编,一部分C/C++编写的。那么他们可以叫做java的源代码。而在刚入门开发中,了解到.class就ok。
1.2 反编译及工具推荐
想要看到.class文件,必须有反编译工具,JD-GUI。然后是api,doc文档。
个人感觉使用IDEA看着更方面一些,而且用到啥就自动下载啥。
二.源码解读
2.1 如何正确阅读
老师在讲Sring课的时候,源码部分都是一带而过。如果只是跟老师的讲课节奏遇到一个看一个,对于源码的掌握就比较缓慢。正确是应该有一个脉络,一个体系,把他们串起来。先从Spring的结构出发,然后在细化到每个具体的方法,最后再去看细节。然后记录思维导图/流程图
2.2 Spring源码入门
知道了如何认识源代码之后,就需要我们找到一个切入点来进行来学习。以最近项目举例,测试的时候经常使用的这条语句。
ApplicationContext ct = new ClassPathXmlApplicationContext("spring.xml");
在这里下一个断点,然后跟踪,之后我们便可以得到一个简略的Spring架构图
为了简化步骤,再分析的时候可以看AbstractApplicationContext
中的refresh()
方法
架构解读:
左边开始,是注入的一些信息,我们目前用到的是xml
配置和annotation
(注解)。有了配置信息,那么一下步理应是生成bean
。但事实上需要对不同的定义形式进行统一封装。这里用到了一个BeanDefinitionReader
。
下一步交给到了BeanDefition
,不过在通过定义创建对象(实例化)之前,还需要走BeanFactory的反射。
由于基础反射的课程本班并没有讲解,所以大家对这块比较陌生。下面用一个反射+自定义注解(非Spring的自动装配)实现一下注解如何如何生成对象。
public class Test2 {
public static void main(String[] args) {
UserController userController = new UserController();
class<? extends UserController> clazz = userController.getClass();
//获取当前controller的属性有哪些
Stream.of(clazz.getDeclaredFields()).forEach(field ->{
//判断一个属性值是否使用了@Autowired修饰
AutoWired annotation = field.getAnnotation(AutoWired.class);
if (annotation!=null){
field.setAccessiable(true);
//获取到属性类型,方便创建对象
Class<?> type = field.getType();
//创建具体对象
Object o = null;
try {
o = type.newInstance();
field.set(userController, 0);
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
});
System.out.println(userController.getUserService());
}
}
接下来到了Bean的生命周期,在老师所讲的步骤外,多了一点东西,比如最开始的Aware接口是做什么用的,初始化之前、初始化之执行的又是什么?FactoryBean又是什么?
2.3 Spring的其他方法解析
FactoryBean
**
* Interface to be implemented by objects used within a {@link BeanFactory} which
* are themselves factories for individual objects. If a bean implements this
* interface, it is used as a factory for an object to expose, not directly as a
* bean instance that will be exposed itself.
*
* <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
* A FactoryBean is defined in a bean style, but the object exposed for bean
* references ({@link #getObject()}) is always the object that it creates.
*
* <p>FactoryBeans can support singletons and prototypes, and can either create
* objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
* interface allows for exposing more fine-grained behavioral metadata.
*
* <p>This interface is heavily used within the framework itself, for example for
* the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
* {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
* custom components as well; however, this is only common for infrastructure code.
*
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
* the bootstrap process, even ahead of any post-processor setup. If you need access
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
*
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
* synchronization of bean creation. There is usually no need for internal
* synchronization other than for purposes of lazy initialization within the
* FactoryBean itself (or the like).
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 08.03.2003
* @param <T> the bean type
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.aop.framework.ProxyFactoryBean
* @see org.springframework.jndi.JndiObjectFactoryBean
*/
public interface FactoryBean<T> {
FactoryBean的三个方法
//返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。
T getObject() throws Exception;
//返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
Class<?> getObjectType();
//返回FactoryBean创建的bean类型。
default boolean isSingleton() {
return true;
}
总结出来一句话:生产唯一特殊复杂对象。
BeanFactoryPostProcessor与BeanPostProcesser
如果我们想对bean对象进行二次加工,那么就会用到这些增强器。也就是最近在学的advice(通知/增强)。详细请参照昨天的内容。
三.总结
上述是个人在源码阶段所认识的内容,由于能力有限,没有深入了解(监听器都没有提到),但对于Spring的认识具有了一定的提升。在对spring的开发有一定经验后可以继续提升。下面附一张SpringBoot2.2.2的启动图供以后学习。