作者:小傅哥

博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!

一、前言

同事写的代码,我竟丝毫看不懂!

大佬的代码,就像 “赖蛤蟆泡青蛙,张的丑玩的花” :一个类实现了多个接口、继承的类又继承了其他类、接口还可以和接口继承、实现接口的抽象类再由类实现抽象类方法、类A继承的类B实现了类A实现的接口C,等等。

看上去复杂又难懂的代码,却又能一次次满足需求的高效迭代和顺利扩展,而像螺丝钉一样搬砖的你,只是在大佬写的代码里,完成某个接口下的一小块功能,甚至写完了也不知道怎么就被调用运行了,整个过程像看 Spring 源码一样神奇,跳来跳去的摸不着头绪!

其实这主要是因为你的代码是否运用了设计模式,当然设计模式也没那么神奇,就像你们两家都是120平米的房子,他家有三室两厅一厨一卫,南北通透,全阳采光。但你家就不一样了,你家是锅碗瓢盆、卫浴马桶、沙发茶几还有那1.8的双人床,在120平米的房子里敞开了放,没有动静隔离,也没有干湿分离,纯自由发挥。所以你的代码看上去就乱的很!

二、目标

目前已实现的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 对象的定义和注册,以及在操作 Bean 对象过程中执行的,BeanFactoryPostProcessor、BeanPostProcessor、InitializingBean、DisposableBean,以及在 XML 新增的一些配置处理,让我们可以 Bean 对象有更强的操作性。

那么,如果我们想获得 Spring 框架提供的 BeanFactory、ApplicationContext、BeanClassLoader等这些能力做一些扩展框架的使用时该怎么操作呢。所以我们本章节希望在 Spring 框架中提供一种能感知容器操作的接口,如果谁实现了这样的一个接口,就可以获取接口入参中的各类能力。

三、设计

如果说我希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后你定义出来的获取方式,在 Spring 框架中该怎么去承接,实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。

在关于 Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实我们如果像获取 Spring 一些如 BeanFactory、ApplicationContext 时,也可以通过此类方式进行实现。那么我们需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用就可以,而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof 进行判断和调用了。整体设计结构如下图:

  • 定义接口 Aware,在 Spring 框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。也就是通过这个桥梁,向具体的实现类中提供容器服务
  • 继承 Aware 的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware,当然在 Spring 源码中还有一些其他关于注解的,不过目前我们还是用不到。
  • 在具体的接口实现过程中你可以看到,一部分(BeanFactoryAware、BeanClassLoaderAware、BeanNameAware)在 factory 的 support 文件夹下,另外 ApplicationContextAware 是在 context 的 support 中,这是因为不同的内容获取需要在不同的包下提供。所以,在 AbstractApplicationContext 的具体实现中会用到向 beanFactory 添加 BeanPostProcessor 内容的 ApplicationContextAwareProcessor 操作,最后由 AbstractAutowireCapableBeanFactory 创建 createBean 时处理相应的调用操作。关于 applyBeanPostProcessorsBeforeInitialization 已经在前面章节中实现过,如果忘记可以往前翻翻

四、实现

1. 工程结构

small-spring-step-08
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework
│ ├── beans
│ │ ├── factory
│ │ │ ├── factory
│ │ │ │ ├── AutowireCapableBeanFactory.java
│ │ │ │ ├── BeanDefinition.java
│ │ │ │ ├── BeanFactoryPostProcessor.java
│ │ │ │ ├── BeanPostProcessor.java
│ │ │ │ ├── BeanReference.java
│ │ │ │ ├── ConfigurableBeanFactory.java
│ │ │ │ └── SingletonBeanRegistry.java
│ │ │ ├── support
│ │ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ │ ├── AbstractBeanDefinitionReader.java
│ │ │ │ ├── AbstractBeanFactory.java
│ │ │ │ ├── BeanDefinitionReader.java
│ │ │ │ ├── BeanDefinitionRegistry.java
│ │ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ │ ├── DefaultListableBeanFactory.java
│ │ │ │ ├── DefaultSingletonBeanRegistry.java
│ │ │ │ ├── DisposableBeanAdapter.java
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── Aware.java
│ │ │ ├── BeanClassLoaderAware.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── BeanFactoryAware.java
│ │ │ ├── BeanNameAware.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── DisposableBean.java
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ ├── InitializingBean.java
│ │ │ └── ListableBeanFactory.java
│ │ ├── BeansException.java
│ │ ├── PropertyValue.java
│ │ └── PropertyValues.java
│ ├── context
│ │ ├── support
│ │ │ ├── AbstractApplicationContext.java
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ ├── ApplicationContextAwareProcessor.java
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.java
│ │ ├── ApplicationContextAware.java
│ │ └── ConfigurableApplicationContext.java
│ ├── core.io
│ │ ├── ClassPathResource.java
│ │ ├── DefaultResourceLoader.java
│ │ ├── FileSystemResource.java
│ │ ├── Resource.java
│ │ ├── ResourceLoader.java
│ │ └── UrlResource.java
│ └── utils
│ └── ClassUtils.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ ├── UserDao.java
│ └── UserService.java
└── ApiTest.java

工程源码公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码

Spring 感知接口的设计和实现类关系,如图 9-2

  • 以上整个类关系就是关于 Aware 感知的定义和对容器感知的实现。
  • Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
  • 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactory 中 createBean 方法下的内容,所以需要像容器中注册 addBeanPostProcessor ,再由 createBean 统一调用 applyBeanPostProcessorsBeforeInitialization 时进行操作。

2. 定义标记接口

cn.bugstack.springframework.beans.factory.Aware

/**
* Marker superinterface indicating that a bean is eligible to be
* notified by the Spring container of a particular framework object
* through a callback-style method. Actual method signature is
* determined by individual subinterfaces, but should typically
* consist of just one void-returning method that accepts a single
* argument.
*
* 标记类接口,实现该接口可以被Spring容器感知
*
*/
public interface Aware {
}
  • 在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有 instanceof 一起判断使用。

3. 容器感知类

3.1 BeanFactoryAware

cn.bugstack.springframework.beans.factory.BeanFactoryAware

public interface BeanFactoryAware extends Aware {

   void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}
  • Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.
  • 实现此接口,既能感知到所属的 BeanFactory

3.2 BeanClassLoaderAware

cn.bugstack.springframework.beans.factory.BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware{

    void setBeanClassLoader(ClassLoader classLoader);

}
  • Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by the present bean factory to load bean classes.
  • 实现此接口,既能感知到所属的 ClassLoader

3.3 BeanNameAware

cn.bugstack.springframework.beans.factory.BeanNameAware

public interface BeanNameAware extends Aware {

    void setBeanName(String name);

}
  • Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
  • 实现此接口,既能感知到所属的 BeanName

3.4 ApplicationContextAware

cn.bugstack.springframework.context.ApplicationContextAware

public interface ApplicationContextAware extends Aware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}
  • Interface to be implemented by any object that wishes to be notifiedof the {@link ApplicationContext} that it runs in.
  • 实现此接口,既能感知到所属的 ApplicationContext

4. 包装处理器(ApplicationContextAwareProcessor)

cn.bugstack.springframework.context.support.ApplicationContextAwareProcessor

public class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ApplicationContext applicationContext;

    public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
} @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware){
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
} }
  • 由于 ApplicationContext 的获取并不能直接在创建 Bean 时候就可以拿到,所以需要在 refresh 操作时,把 ApplicationContext 写入到一个包装的 BeanPostProcessor 中去,再由 AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization 方法调用。

5. 注册 BeanPostProcessor

cn.bugstack.springframework.context.support.AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    @Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory(); // 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
invokeBeanFactoryPostProcessors(beanFactory); // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory); // 6. 提前实例化单例Bean对象
beanFactory.preInstantiateSingletons();
} // ...
}
  • refresh() 方法就是整个 Spring 容器的操作过程,与上一章节对比,本次新增加了关于 addBeanPostProcessor 的操作。
  • 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext。

6. 感知调用操作

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
// 给 Bean 填充属性
applyPropertyValues(beanName, bean, beanDefinition);
// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
} // 注册实现了 DisposableBean 接口的 Bean 对象
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition); addSingleton(beanName, bean);
return bean;
} private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) { // invokeAwareMethods
if (bean instanceof Aware) {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
if (bean instanceof BeanClassLoaderAware){
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
} // 1. 执行 BeanPostProcessor Before 处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName); // 执行 Bean 对象的初始化方法
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
} // 2. 执行 BeanPostProcessor After 处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return wrappedBean;
} @Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (null == current) return result;
result = current;
}
return result;
} @Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (null == current) return result;
result = current;
}
return result;
} }
  • 这里我们去掉了一些类的内容,只保留关于本次 Aware 感知接口的操作。
  • 首先在 initializeBean 中,通过判断 bean instanceof Aware,调用了三个接口方法,BeanFactoryAware.setBeanFactory(this)BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())BeanNameAware.setBeanName(beanName),这样就能通知到已经实现了此接口的类。
  • 另外我们还向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此时在这个方法中也会被调用到具体的类实现,得到一个 ApplicationContex 属性。

五、测试

1. 事先准备

cn.bugstack.springframework.test.bean.UserDao

public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    public void initDataMethod(){
System.out.println("执行:init-method");
hashMap.put("10001", "小傅哥");
hashMap.put("10002", "八杯水");
hashMap.put("10003", "阿毛");
} public void destroyDataMethod(){
System.out.println("执行:destroy-method");
hashMap.clear();
} public String queryUserName(String uId) {
return hashMap.get(uId);
} }

cn.bugstack.springframework.test.bean.UserService

public class UserService implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware {

    private ApplicationContext applicationContext;
private BeanFactory beanFactory; private String uId;
private String company;
private String location;
private UserDao userDao; @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
} @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
} @Override
public void setBeanName(String name) {
System.out.println("Bean Name is:" + name);
} @Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("ClassLoader:" + classLoader);
} // ...get/set
}
  • UserDao 本次并没有什么改变,还是提供了关于初始化的方法,并在 Spring.xml 中提供 init-method、destroy-method 配置信息。
  • UserService 新增加,BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware,四个感知的实现类,并在类中实现相应的接口方法。

2. 配置文件

基础配置,无BeanFactoryPostProcessor、BeanPostProcessor,实现类

<?xml version="1.0" encoding="UTF-8"?>
<beans> <bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/> <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService">
<property name="uId" value="10001"/>
<property name="company" value="腾讯"/>
<property name="location" value="深圳"/>
<property name="userDao" ref="userDao"/>
</bean> </beans>
  • 本章节中并没有额外新增加配置信息,与上一章节内容相同。

3. 单元测试

@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook(); // 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
System.out.println("ApplicationContextAware:"+userService.getApplicationContext());
System.out.println("BeanFactoryAware:"+userService.getBeanFactory());
}
  • 测试方法中主要是添加了一写关于新增 Aware 实现的调用,其他不需要调用的也打印了相应的日志信息,可以在测试结果中看到。

测试结果

执行:init-method
ClassLoader:sun.misc.Launcher$AppClassLoader@14dad5dc
Bean Name is:userService
测试结果:小傅哥,腾讯,深圳
ApplicationContextAware:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@5ba23b66
BeanFactoryAware:cn.bugstack.springframework.beans.factory.support.DefaultListableBeanFactory@2ff4f00f
执行:destroy-method Process finished with exit code 0
  • 从测试结果可以看到,本章节新增加的感知接口对应的具体实现(BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware),已经可以如期输出结果了。

六、总结

  • 目前关于 Spring 框架的实现中,某些功能点已经越来趋向于完整,尤其是 Bean 对象的生命周期,已经有了很多的体现。整体总结如图 9-3

  • 本章节关于 Aware 的感知接口的四个继承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 的实现,又扩展了 Spring 的功能。如果你有做过关于 Spring 中间件的开发那么一定会大量用到这些类,现在你不只是用过,而且还知道他们都是什么时候触达的,在以后想排查类的实例化顺序也可以有一个清晰的思路了。

  • 每一章节内容的实现都是在以设计模式为核心的结构上填充各项模块的功能,单纯的操作编写代码并不会有太多收获,一定是要理解为什么这么设计,这么设计的好处是什么,怎么就那么多接口和抽象类的应用,这些才是 Spring 框架学习的核心所在。

七、系列推荐

手写Spring,定义标记类型Aware接口,实现感知容器对象的更多相关文章

  1. 手写Spring AOP,快来瞧一瞧看一看撒!

    目录 AOP分析 Advice实现 定义Advice接口 定义前置.后置.环绕和异常增强接口 Pointcut实现 定义PointCut接口 定义正则表达式的实现类:RegExpressionPoin ...

  2. 【Spring】手写Spring MVC

    Spring MVC原理 Spring的MVC框架主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成. 完整的Spring MVC处理 流程如下: Sprin ...

  3. 手写Spring框架,加深对Spring工作机制的理解!

    在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越 ...

  4. 手写Spring事务框架

    Spring事务基于AOP环绕通知和异常通知 编程事务 声明事务 Spring事务底层使用编程事务+AOP进行包装的   = 声明事务 AOP应用场景:  事务 权限 参数验证 什么是AOP技术 AO ...

  5. -手写Spring注解版本&事务传播行为

    视频参考C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0018-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Spri ...

  6. 手写spring事务框架-蚂蚁课堂

    1.视频参加C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0017-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Sp ...

  7. 手写spring

    体系结构 Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入.下面的部分对在 Spring 框架中所有可用的 ...

  8. 手写Spring DI依赖注入,嘿,你的益达!

    目录 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBeanFa ...

  9. 手写Spring Config,最终一战,来瞅瞅撒!

    上一篇说到了手写Spring AOP,来进行功能的增强,下面本篇内容主要是手写Spring Config.通过配置的方式来使用Spring 前面内容链接: 我自横刀向天笑,手写Spring IOC容器 ...

随机推荐

  1. CRM客户关系管理系统有哪些优缺点?

    CRM系统不仅仅是一种技术,也是面向企业的客户管理系统.客户关系管理软件可以帮助销售员快速地找到客户信息,帮助销售员跟踪客户直到完成订单.为提高企业销售效率,CRM被越来越多的企业所采用. 那么,作为 ...

  2. 【Web前端HTML5&CSS3】06-盒模型

    笔记来源:尚硅谷Web前端HTML5&CSS3初学者零基础入门全套完整版 目录 盒模型 1. 文档流(normalflow) 2. 块元素 3. 行内元素 4. 盒子模型 盒模型.盒子模型.框 ...

  3. docker-compose如何动态配置springboot项目的application.yml的配置

    假如我们再springboot的工程中有配置文件 方式1: application.properties里面存在环境变量: #配置数据库链接 spring.datasource.url = jdbc: ...

  4. mysql知识点归纳-锁(死锁)

    愿历尽千帆,归来仍是少年 所遇问题: MySql 更新死锁问题 Deadlock found when trying to get lock; try restarting transaction 场 ...

  5. [bug] Job for network.service failed because the control process exited with error code

    原因 复制虚拟机,没有改网卡配置文件 参考 https://blog.csdn.net/dongfei2033/article/details/81124465

  6. [刷题] PTA 6-11 求自定类型元素序列的中位数 (25分)

    采用希尔排序 1 #include <stdio.h> 2 3 #define MAXN 10 4 typedef float ElementType; 5 6 ElementType M ...

  7. [项目] 淘淘商城 Part.1

    电商 市场 2013:79万笔/分钟 2014:13.4万亿,双11支付宝交易峰值285万笔/分钟 2015:50万亿 技术特点 一个Tomcat:500并发 分布式:上万并发 高并发.集群.负载均衡 ...

  8. 042.Python进程队列介绍

    进程队列介绍 1  基本语法及过程 先进先出,后进后出,q = Queue() 过程 (1)把数据放到q队列中 put (2)把书局从队列中拿出来 get from multiprocessing i ...

  9. Linux进阶之Jenkins持续集成介绍及安装演示

    一.Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. Jenkins功能包 ...

  10. IDEA 查看类图功能(分析源码的利器)

    引言 做过项目开发的童靴,应该会有这样的经历,就是刚进公司领导二话不说直接丢个项目,而且没有任何文档,让熟悉一下,一两周就让上手写代码.打开项目后就看到一堆类源码,完全不知道从何处入手,应该如何分析项 ...