[适合初中级Java程序员修炼手册从0搭建整个Web项目](三)(上)

简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

six-finger-web


一个Web后端框架的轮子从处理Http请求【基于Netty的请求级Web服务器】 到mvc【接口封装转发)】,再到ioc【依赖注入】,aop【切面】,再到 rpc【远程过程调用】最后到orm【数据库操作】全部自己撸一个(简易)的轮子。

github


为啥要写这个轮子



其实是这样的,小六六自己平时呢?有时候喜欢看看人家的源码比如Spring,但是小六六的水平可能不怎么样,每次看都看得晕头转向,然后就感觉里面的细节太难了,然后我就只能观其总体的思想,然后我就想我如果可以根据各位前辈的一些思考,自己撸一个简单的轮子出来,那我后面去理解作者的思想是不是简单点呢?于是呢 six-finger-web就面世了,它其实就是我的一个学习过程,然后我把它开源出来,希望能帮助那些对于学习源码有困难的同学。还有就是可以锻炼一下自己的编码能力,因为平时我们总是crud用的Java api都是那些,久而久之,很多框架类的api我们根本就不熟练了,所以借此机会,锻炼一下。


特点


  • 内置由 Netty 编写 HTTP 服务器,无需额外依赖 Tomcat 之类的 web 服务(刚好小六六把Netty系列写完,顺便用下)
  • 代码简单易懂(小六六自己写不出框架大佬那种高类聚,低耦合的代码),能力稍微强一点看代码就能懂,弱点的也没关系,小六六有配套的从0搭建教程。
  • 支持MVC相关的注解确保和SpringMVC的用法类似
  • 支持Spring IOC 和Aop相关功能
  • 支持类似于Mybatis相关功能
  • 支持类似于Dubbo的rpc相关功能
  • 对于数据返回,只支持Json格式


絮叨

今天呢 我们来搭建一下Spring IOC, 其实这个东西也是老生常谈的东西了,今天先出一个基于注解的,下次补一个基于xml的,上次说的基于Servlet的MVC后面也会补,大家一起慢慢来。小六六也是跟大家一起学习。其实我们知道,不管是基于 注解,还是基于XML,他们的不同在于生成BeanDefinition,只要得到他之后呢?后面的其实就是通用的了。 好了,下面我给大家来一一走一遍搭建流程

这边建议一边下载源码,一边来看,如果觉得有问题的话


大家来看看,今天完成之后的包结构


网络异常,图片无法展示
|


先说整体流程,所谓的IOC容器,就是控制反转之后,我们把bean存放的地方,也就是在Java中其实也就是map,所以大致的初始化流程,就是先扫描注解,和xml 生成我们Beandefinition,然后再生成Bean,然后再提供给外面使用,整体的流程就是这么简单,但是里面Spring的实现,我真的是佩服,反正我是看源码看得云里雾里的,各种抽象和封装,可能这种编码能力和思想就是我们所欠缺的。


看看我的演示

  • 启动类

网络异常,图片无法展示
|

  • UserController

网络异常,图片无法展示
|


  • UserServiceImpl

网络异常,图片无法展示
|

  • 请求参数

http://localhost:8081/user/yes

  • 结果

网络异常,图片无法展示
|


BeanFactory

BeanFactory是IOC容器的顶层父接口,大名鼎鼎的 ApplicationContext就是继承它,它定义了我们最常用的获取Bean的方法。

package com.xiaoliuliu.six.finger.web.spring.ioc.factory;
/**
 * @author 小六六
 * @version 1.0
 * @date 2020/10/19 10:08
 * 这个接口也是Spring ioc的核心接口呢,总的来说,Siprng ioc的实现了 我们需要实现2种,一种是基于注解的实现,一种是基于xml的实现
 */
public interface BeanFactory {
    Object getBean(String name) throws Exception;
    <T> T getBean(Class<T> requiredType) throws Exception;
}
复制代码


ApplicationContext

ApplicationContext 我们非常熟悉,继承了BeanFactory、MessageSource、ApplicationEventPublisher等等接口,功能非常强大

/**
 * 空接口,大家明白就好
 * 原接口需要继承ListableBeanFactory, HierarchicalBeanFactory等等,这里就简单继承BeanFactory 
 **/
public interface ApplicationContext extends BeanFactory {
}
复制代码


DefaultApplicationContext

相信大家都知道,ApplicationContext 实现类中最重要的就是 refresh() 方法,它的流程就包括了IOC容器初始化依赖注入AOP,方法中的注释已经写的很明白了。

public class DefaultApplicationContext implements ApplicationContext {
    //配置文件路径
    private String configLocation;
    public DefaultApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        try {
            refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void refresh() throws Exception {
        //1、定位,定位配置文件
        //2、加载配置文件,扫描相关的类,把它们封装成BeanDefinition
        //3、注册,把配置信息放到容器里面(伪IOC容器)
        //到这里为止,容器初始化完毕
        //4、把不是延时加载的类,提前初始化
    }
  @Override
    public Object getBean(String beanName) throws Exception {
        return null;
    }
  @Override
    public <T> T getBean(Class<T> requiredType) throws Exception {
        return (T) getBean(requiredType.getName());
    }
}
复制代码


成员变量configLocation保存了我们的配置文件路径,所以这里就先把这个配置文件先新建出来。在resource目录下需要新建一个配置文件application.properties,并且指定扫描的包路径。

scanPackage=
复制代码

BeanDefinition

我们原来使用xml作为配置文件时,定义的Bean其实在IOC容器中被封装成了BeanDefinition,也就是Bean的配置信息,包括className、是否为单例、是否需要懒加载等等。它是一个interface,这里我们直接定义成class。

@Data
public class BeanDefinition {
    private String beanClassName;
    private boolean lazyInit = false;
    private String factoryBeanName;
    public BeanDefinition() {}
}
复制代码


BeanDefinitionReader

public class BeanDefinitionReader {
    //配置文件
    private Properties config = new Properties();
    //配置文件中指定需要扫描的包名
    private final String SCAN_PACKAGE = "scanPackage";
     public BeanDefinitionReader(String... locations) {
     }
  public Properties getConfig() {
         return config;
     }
 }
复制代码


BeanWrapper

当BeanDefinition的Bean配置信息被读取并实例化成一个实例后,这个实例封装在BeanWrapper中。

public class BeanWrapper {
    /**Bean的实例化对象*/
    private Object wrappedObject;
    public BeanWrapper(Object wrappedObject) {
        this.wrappedObject = wrappedObject;
    }
    public Object getWrappedInstance() {
        return this.wrappedObject;
    }
    public Class<?> getWrappedClass() {
        return getWrappedInstance().getClass();
    }
}
复制代码


读取配置文件

前面几个基础的类已经搭建好了,接下来就是定位和解析配置文件。这边是基于注解来生成Beandefinition。

在DefaultApplicationContext中,我们先完成第一步,定位和解析配置文件。

private void refresh() throws Exception {
    //1、定位,定位配置文件
    reader = new BeanDefinitionReader(this.configLocation);
    //2、加载配置文件,扫描相关的类,把它们封装成BeanDefinition
    //3、注册,把配置信息放到容器里面
    //到这里为止,容器初始化完毕
    //4、把不是延时加载的类,提前初始化
}
复制代码


完成BeanDefinitionReader中的构造方法,流程分为三步走:

  • 将我们传入的配置文件路径解析为文件流
  • 将文件流保存为Properties,方便我们通过Key-Value的形式来读取配置文件信息
  • 根据配置文件中配置好的扫描路径,开始扫描该路径下的所有class文件并保存到集合中
/**保存了所有Bean的className*/
private List<String> registyBeanClasses = new ArrayList<>();
public BeanDefinitionReader(String... locations) {
    try(
        //1.定位,通过URL定位找到配置文件,然后转换为文件流
        InputStream is = this.getClass().getClassLoader()
                .getResourceAsStream(locations[0].replace("classpath:", ""))) {
        //2.加载,保存为properties
        config.load(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //3.扫描,扫描资源文件(class),并保存到集合中
    doScanner(config.getProperty(SCAN_PACKAGE));
}
复制代码


相关文章
|
8天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1400 10
|
8天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
1257 5
|
9天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
1107 14
|
3天前
|
人工智能 前端开发 API
Google发布50页AI Agent白皮书,老金帮你提炼10个核心要点
老金分享Google最新AI Agent指南:让AI从“动嘴”到“动手”。Agent=大脑(模型)+手(工具)+协调系统,可自主完成任务。通过ReAct模式、多Agent协作与RAG等技术,实现真正自动化。入门推荐LangChain,文末附开源知识库链接。
396 118
|
6天前
|
存储 缓存 NoSQL
阿里云经济型e实例(ecs.e-c1m4.large)2核8G云服务器优惠活动价格及性能测评
阿里云经济型e实例(ecs.e-c1m4.large)2核8G配置,支持按使用流量或按固定带宽两种公网计费方式,搭配20G起ESSD Entry云盘,是主打高性价比的内存优化型入门选择。其核心特点是8G大内存适配轻量内存密集场景,计费模式灵活可控,既能满足个人开发者的复杂测试项目需求,也能支撑小微企业的基础业务运行,无需为闲置资源过度付费。以下从优惠活动价格、性能表现、适用场景及避坑要点四方面,用通俗语言详细解析。
224 153
|
3天前
|
机器学习/深度学习 人工智能 算法
炎鹊「Nexus Agent V1.0」:垂直领域AI应用的原生能力引擎
炎鹊AI「Nexus Agent V1.0」是垂直行业专属AI原生引擎,融合大模型、AIGA决策大脑、行业知识图谱与专属模型,打造“感知-决策-执行”闭环。支持21个行业低代码构建工具型、员工型、决策型AI应用,实现技术到业务价值的高效转化,推动AI从实验走向规模化落地。(239字)
242 1

热门文章

最新文章