Backend Development 23 min read

Understanding Spring Core Concepts and Building a Minimal Servlet‑Based Framework

This article explains Spring's core features such as IoC, DI, and AOP, demonstrates a simple Hello World application with Spring Boot, then shows how to implement the same functionality using raw Servlets and a handcrafted mini‑Spring framework, complete with code examples and deployment steps.

Java Captain
Java Captain
Java Captain
Understanding Spring Core Concepts and Building a Minimal Servlet‑Based Framework

Preface

With the rise of Spring and its extensive ecosystem, most modern Java projects use the Spring family for development. Spring simplifies many tasks, and Spring Boot further reduces configuration, but relying heavily on it can make developers uneasy when they need to work without the framework, especially if they have never written raw Servlet code.

1. What Spring Can Do for Us

Spring is designed to simplify enterprise‑level application development. All objects in Spring are beans, enabling Bean‑Oriented Programming (BOP) combined with Dependency Injection (DI) and Aspect‑Oriented Programming (AOP).

1.1 Inversion of Control (IoC)

IoC means developers no longer instantiate objects directly with new ; instead, the container creates and injects them.

1.2 Dependency Injection (DI)

DI is the concrete mechanism by which Spring implements IoC, automatically wiring required dependencies.

1.3 Aspect‑Oriented Programming (AOP)

AOP encapsulates cross‑cutting concerns (e.g., authentication, caching, error handling, logging, transactions) into reusable modules called aspects.

1.4 Hello World with Spring Boot

Using Spring Boot, a minimal Hello World service can be created with just a few classes.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
package com.lonely.wolf.note.springboot.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {
    @GetMapping("/demo")
    public String helloWorld(String name){
        return "Hello:" + name;
    }
}
package com.lonely.wolf.note.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.lonely.wolf.note.springboot")
class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

Running the application and accessing http://localhost:8080/hello/demo?name=YourName returns Hello:YourName . Spring Boot achieves this with virtually no XML configuration because it follows the "convention over configuration" principle and embeds an embedded Tomcat server.

2. What If Spring Is Not Available?

If we cannot rely on Spring, we must implement the same functionality using raw Servlets.

2.1 Servlet‑Based Development

First, create a Maven war project and add the necessary dependencies:

<packaging>war</packaging>
<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.7</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.72</version>
    </dependency>
</dependencies>

Define web.xml to map a servlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4">
    <display-name>Lonely Wolf Web Application</display-name>
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.lonely.wolf.mini.spring.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
</web-app>

Implement the servlet:

package com.lonely.wolf.mini.spring.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Simple HelloServlet handling GET and POST.
 */
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("Hello:" + request.getParameter("name"));
    }
}

Package the project as a war , deploy it to Tomcat, and access http://localhost:8080/hello?name=YourName to receive the same greeting. Compared with Spring Boot, this approach requires explicit XML configuration and manual servlet registration.

2.2 Mimicking Spring with a Mini‑Framework

To illustrate Spring's core ideas without using the full framework, a tiny "mini‑Spring" is built. The project defines custom annotations ( @WolfController , @WolfService , @WolfAutowired , @WolfGetMapping , @WolfRequestParam ) and a dispatcher servlet that performs component scanning, IoC container creation, dependency injection, and handler mapping.

Key files:

package com.lonely.wolf.mini.spring.annotation;

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WolfAutowired { String value() default ""; }
package com.lonely.wolf.mini.spring.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WolfController { String value() default ""; }
package com.lonely.wolf.mini.spring.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WolfGetMapping { String value() default ""; }

The central dispatcher servlet ( MyDispatcherServlet ) performs the following steps during initialization:

Load application.properties to obtain the base package to scan.

Recursively scan the package, collect fully‑qualified class names, and store them in classNameList .

Instantiate classes annotated with @WolfController or @WolfService and put them into iocContainerMap (the IoC container).

Inject fields marked with @WolfAutowired by looking up the corresponding bean in the container.

Build handlerMappingMap by combining controller‑level and method‑level request paths ( @WolfGetMapping ) and storing method parameter metadata.

During a request, doDispatch matches the URL, resolves parameters (including HttpServletRequest , HttpServletResponse , and String parameters annotated with @WolfRequestParam ), and invokes the target method via reflection.

Supporting classes:

package com.lonely.wolf.mini.spring.v1;

import java.lang.reflect.Method;
import java.util.Map;

public class HandlerMapping {
    private String requestUrl;
    private Object target;
    private Method method;
    private Map
methodParams;
    // getters and setters omitted for brevity
}

Example controller and service used for testing:

package com.lonely.wolf.mini.spring.controller;

import com.lonely.wolf.mini.spring.annotation.*;
import com.lonely.wolf.mini.spring.service.HelloService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WolfController
public class HelloController {
    @WolfAutowired
    private HelloService helloService;

    @WolfGetMapping("/hello")
    public void query(HttpServletRequest request, HttpServletResponse response, @WolfRequestParam("name") String name) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("Hello:" + name);
    }
}
package com.lonely.wolf.mini.spring.service;

import com.lonely.wolf.mini.spring.annotation.WolfService;

@WolfService(value = "hello_service")
public class HelloService { }

After deploying the war , accessing http://localhost:8080/hello?name=YourName triggers the mini‑framework, which resolves the request to HelloController.query and returns the greeting.

Conclusion

The article first introduced Spring's core concepts, showed how to create a simple Hello World service with Spring Boot, then demonstrated how to achieve the same result using raw Servlets, and finally built a tiny Spring‑like framework to illustrate IoC, DI, and request mapping without any external libraries.

JavaIoCSpringWeb Developmentdependency injectionServletMini Framework
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.