端午特别篇-Spring源码解读

Posted 滨奇科技

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了端午特别篇-Spring源码解读相关的知识,希望对你有一定的参考价值。

警告:今天的内容可能会使您感到不适!!!



前景引入:

        从线下课开始到现在,常常会听到老师说一句话,Ctrl点击去一下。一般我们会得到一个我们自己写的方法。但是,如果点的是环境提供(JDK)的方法呢,再点进去之后是啥样呢(debug时也会遇见),在文件的导航栏看到的是一个.class的文件,下面是一段java代码。到这里很多同学的Eclipse就查看不到了。于是问老师,老师这边呢,给出了一个这样的说法:我的Eclipse带反编译,你需要反编译环境才可以看到。

最近在讲到Spring时也会提到,这是底层实现的,有兴趣的同学可以去看下。

到这里,引入了两个关键词,反编译,底层。那么这到底是什么东西呢?对于我们以后的发展,及对问题的解决是否会提供思路呢?答案是肯定的。


一.源代码与反编译


1.1  源代码


在我们学习Java前,还学过C语言,更底层一点是汇编语言,最后是0101这些二进制。

端午特别篇(二)-Spring源码解读

通过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架构图


端午特别篇(二)-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容器中单实例缓存池中。@NullableT getObject() throws Exception;//返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。@NullableClass<?> getObjectType();//返回FactoryBean创建的bean类型。default boolean isSingleton() { return true;}


总结出来一句话:生产唯一特殊复杂对象。

  • BeanFactoryPostProcessor与BeanPostProcesser

如果我们想对bean对象进行二次加工,那么就会用到这些增强器。也就是最近在学的advice(通知/增强)。详细请参照昨天的内容。


三.总结


上述是个人在源码阶段所认识的内容,由于能力有限,没有深入了解(监听器都没有提到),但对于Spring的认识具有了一定的提升。在对spring的开发有一定经验后可以继续提升。下面附一张SpringBoot2.2.2的启动图供以后学习。


以上是关于端午特别篇-Spring源码解读的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码解读之核心容器下节

ArrayList源码解读

Vue源码解读——变化侦测篇

SpringBoot源码解读系列二——依赖配置

Spring源码解读---底层核心原理解析

Spring源码解读---底层核心原理解析