RepoPilotOpen in app →

code4craft/tiny-spring

A tiny IoC container refer to Spring.

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyMixed

last commit was 2y ago; no CI workflows detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 2y ago; no CI workflows detected

  • 4 active contributors
  • Apache-2.0 licensed
  • Tests present
Show all 7 evidence items →
  • Stale — last commit 2y ago
  • Small team — 4 contributors active in recent commits
  • Single-maintainer risk — top contributor 89% of recent commits
  • No CI workflows detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/code4craft/tiny-spring?axis=fork)](https://repopilot.app/r/code4craft/tiny-spring)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/code4craft/tiny-spring on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: code4craft/tiny-spring

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/code4craft/tiny-spring shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 4 active contributors
  • Apache-2.0 licensed
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Small team — 4 contributors active in recent commits
  • ⚠ Single-maintainer risk — top contributor 89% of recent commits
  • ⚠ No CI workflows detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live code4craft/tiny-spring repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/code4craft/tiny-spring.

What it runs against: a local clone of code4craft/tiny-spring — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in code4craft/tiny-spring | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 923 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>code4craft/tiny-spring</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of code4craft/tiny-spring. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/code4craft/tiny-spring.git
#   cd tiny-spring
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of code4craft/tiny-spring and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "code4craft/tiny-spring(\\.git)?\\b" \\
  && ok "origin remote is code4craft/tiny-spring" \\
  || miss "origin remote is not code4craft/tiny-spring (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/main/java/us/codecraft/tinyioc/aop/AbstractAopProxy.java" \\
  && ok "src/main/java/us/codecraft/tinyioc/aop/AbstractAopProxy.java" \\
  || miss "missing critical file: src/main/java/us/codecraft/tinyioc/aop/AbstractAopProxy.java"
test -f "src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java" \\
  && ok "src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java" \\
  || miss "missing critical file: src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java"
test -f "src/main/java/us/codecraft/tinyioc/beans/xml/XmlBeanDefinitionReader.java" \\
  && ok "src/main/java/us/codecraft/tinyioc/beans/xml/XmlBeanDefinitionReader.java" \\
  || miss "missing critical file: src/main/java/us/codecraft/tinyioc/beans/xml/XmlBeanDefinitionReader.java"
test -f "src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java" \\
  && ok "src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java" \\
  || miss "missing critical file: src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java"
test -f "src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java" \\
  && ok "src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java" \\
  || miss "missing critical file: src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 923 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~893d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/code4craft/tiny-spring"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

tiny-spring is a minimal, educational implementation of Spring Framework's IoC (Inversion of Control) container in ~100KB of Java code. It demonstrates core Spring functionality: bean lifecycle management with singleton support, XML configuration parsing, property and dependency injection, and AspectJ-based AOP with JDK dynamic proxies and CGLIB class proxies. Monolithic jar structure: src/main/java/com/ysj/tinySpring/ contains three sub-packages—beans/ (BeanFactory, BeanDefinition, property injection), aop/ (Advisor, Pointcut, proxy factories), and context/ (ApplicationContext, XML reader)—plus beans/io/ for resource loading and beans/xml/ for XML parsing. Tests are co-located in src/test/java/com/ysj/.

👥Who it's for

Java developers learning Spring internals, architecture students studying IoC containers, and engineers wanting to understand how dependency injection frameworks work without Spring's production complexity. Contributors are typically educational learners following the tagged milestones (step-1 through step-N) to build understanding incrementally.

🌱Maturity & risk

Experimental/Educational. The repo shows no recent commits in the provided data, has minimal test coverage (only BeanFactoryTest.java visible), and lacks CI/CD setup in the pom.xml snippet. This is intentionally a teaching project, not production-ready—the README explicitly frames it as 'a learning version of Spring' by reference rather than for real use.

Very high risk for production: single maintainer (code4craft), no active development signal, bare-bones test suite, and zero error handling visible in core classes. Dependencies on outdated AspectJ (1.6.11) and CGLIB (2.1_3) from ~2011 create compatibility and security unknowns. The codebase prioritizes pedagogical simplicity over robustness.

Active areas of work

No recent activity visible. The repo appears frozen at a stable teaching state with git tags marking milestones (e.g., step-1-container-register-and-get) documented in changelog.md. No open PRs, issues, or development branches are indicated in the file listing.

🚀Get running

git clone https://github.com/code4craft/tiny-spring.git
cd tiny-spring
mvn clean install
mvn test

Optionally, check out a specific milestone: git checkout step-1-container-register-and-get (see changelog.md for all tags).

Daily commands: mvn test runs the test suite. No dev server—this is a library. Import ClassPathXmlApplicationContext.java and call getBean() to use it programmatically (see test examples in src/test/java).

🗺️Map of the codebase

  • src/main/java/us/codecraft/tinyioc/aop/AbstractAopProxy.java — Core abstraction for AOP proxy creation; implements both JDK and CGLIB proxy strategies and is the foundation for cross-cutting concerns
  • src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java — Central bean lifecycle manager; orchestrates bean instantiation, dependency injection, and post-processing—every bean creation flows through here
  • src/main/java/us/codecraft/tinyioc/beans/xml/XmlBeanDefinitionReader.java — Entry point for XML configuration parsing; converts bean definitions from XML into the container's internal representation
  • src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java — High-level container facade that orchestrates bean factory initialization, resource loading, and context lifecycle
  • src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java — AspectJ expression matcher for pointcut evaluation; critical for determining which methods should be intercepted by advice
  • src/main/java/us/codecraft/tinyioc/beans/BeanDefinition.java — Core data structure holding bean metadata (class, properties, scope); referenced throughout bean lifecycle and factory logic
  • src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java — Post-processor that automatically wraps beans with AOP proxies based on advisor matching; bridges bean factory and AOP framework

🛠️How to make changes

Add a new bean definition from XML

  1. Define the new bean class with a no-arg constructor and JavaBean-style setters for properties (src/main/java/us/codecraft/tinyioc/beans/BeanDefinition.java)
  2. Add a <bean> element to the XML configuration file (e.g., tinyioc.xml) with id, class, and <property> children (src/test/resources/tinyioc.xml)
  3. Create ApplicationContext instance pointing to the XML; bean is automatically loaded via XmlBeanDefinitionReader (src/main/java/us/codecraft/tinyioc/context/ClassPathXmlApplicationContext.java)
  4. Retrieve the bean using getBean() method; dependency injection happens automatically in AbstractBeanFactory (src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java)

Add AOP advice with AspectJ expressions

  1. Create an advice class implementing MethodInterceptor from aopalliance; define the invoke() method logic (src/main/java/us/codecraft/tinyioc/aop/AspectJAroundAdvice.java)
  2. Create an AspectJExpressionPointcutAdvisor bean with pointcut expression (e.g., execution(* *.output(..))) (src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcutAdvisor.java)
  3. Register the advisor in the bean factory; AspectJAwareAdvisorAutoProxyCreator will auto-detect and apply proxies (src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java)
  4. Add advisor bean definition to XML or register via bean factory; proxies are created transparently during bean initialization (src/test/resources/tinyioc.xml)

Implement a custom BeanPostProcessor for bean initialization logic

  1. Create a class implementing BeanPostProcessor with postProcessBeforeInitialization() and postProcessAfterInitialization() methods (src/main/java/us/codecraft/tinyioc/beans/BeanPostProcessor.java)
  2. Register the post-processor bean in XML or programmatically via AbstractBeanFactory.addBeanPostProcessor() (src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java)
  3. The post-processor is automatically invoked on every bean during creation; use it for initialization callbacks or bean wrapping (src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java)

Support beans that depend on the BeanFactory itself

  1. Make your bean class implement BeanFactoryAware interface with setBeanFactory() method (src/main/java/us/codecraft/tinyioc/aop/BeanFactoryAware.java)
  2. AbstractBeanFactory checks for this interface and injects the factory instance during bean creation (src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java)

🪤Traps & gotchas

No error handling: ClassNotFoundException in XmlBeanDefinitionReader is swallowed silently; missing beans fail cryptically. Static BeanFactory state: Singleton caching in AbstractBeanFactory is thread-unsafe (no synchronization). XML parsing fragility: Naive DOM parsing in XmlBeanDefinitionReader assumes well-formed input; namespace prefixes not handled. AspectJ version lock: aspectjweaver 1.6.11 is ancient; pointcut matching may fail on modern Java. Circular dependency: No detection; infinite loops possible during bean initialization. ClassLoader assumptions: UrlResource uses hardcoded file:// protocol; classpath: resources require ResourceLoader swaps.

🏗️Architecture

💡Concepts to learn

  • spring-projects/spring-framework — The official Spring Framework—tiny-spring is explicitly built as a simplified reference implementation of its IoC and AOP subsystems
  • google/guice — Lightweight IoC container alternative; similar dependency injection goal with a different API and smaller footprint
  • PivotalLabs/spring-boot — Production Spring distribution; shows how real IoC containers scale and integrate with ecosystem libraries
  • code4craft/webmagic — Another educational project by the same maintainer demonstrating web scraping; useful for seeing how to structure Java learning repos
  • dugu9sword/dugu-spring-annotation — Fork/companion that adds annotation-driven bean registration (@Component, @Autowired) on top of tiny-spring's XML foundation

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for BeanPostProcessor lifecycle

The repo has BeanPostProcessor.java in beans but only one test file (tinyioc-postbeanprocessor.xml) and no dedicated unit tests for BeanPostProcessor implementations. This is critical since BeanPostProcessor is a core extension point in the container. New contributors should add tests covering: multiple post-processors execution order, exception handling during post-processing, and interaction with property injection.

  • [ ] Create src/test/java/com/ysj/beans/BeanPostProcessorTest.java
  • [ ] Add tests for post-processor ordering when multiple processors are registered
  • [ ] Add tests for exception handling and recovery in BeanPostProcessor.postProcessBeforeInitialization() and postProcessAfterInitialization()
  • [ ] Add integration test showing BeanPostProcessor modifying bean properties before initialization

Add missing test coverage for autowiring capabilities in AutowireCapableBeanFactory

The AutowireCapableBeanFactory.java exists but there's no dedicated test file for it (src/test/java/com/ysj/beans/factory/ is empty except potentially). Autowiring is a fundamental feature - tests should cover constructor injection, setter injection, circular dependency detection, and type-based vs name-based autowiring.

  • [ ] Create src/test/java/com/ysj/beans/factory/AutowireCapableBeanFactoryTest.java
  • [ ] Add test for setter-based property autowiring by type
  • [ ] Add test for constructor autowiring with multiple candidates
  • [ ] Add test for circular dependency detection and error handling
  • [ ] Add test for BeanReference resolution during autowiring

Add integration tests for AOP with ApplicationContext and BeanPostProcessor interaction

The repo has separate tests for JdkDynamicAopProxy, Cglib2AopProxy, and AspectJExpressionPointcut, but lacks integration tests showing how AspectJAwareAdvisorAutoProxyCreator works within ApplicationContext lifecycle. This is critical since AOP proxy creation must happen at the right time during bean initialization.

  • [ ] Create src/test/java/com/ysj/aop/AspectJAwareAdvisorAutoProxyCreatorTest.java
  • [ ] Add test showing proxy creation for beans matching AspectJ pointcut expressions
  • [ ] Add test verifying proxy is created before BeanPostProcessor.postProcessAfterInitialization()
  • [ ] Add test with XML configuration (new resource file) showing auto-proxying of multiple beans
  • [ ] Add test for proxy creation with both interface-based and class-based targets

🌿Good first issues

  • Add thread-safe singleton creation: Wrap AbstractBeanFactory.singletonObjects in Collections.synchronizedMap() and add double-check locking to getBean() to prevent race conditions during first instantiation.
  • Write integration tests for circular dependency detection: Create two beans that reference each other (A→B→A) and verify the container throws BeanCreationException with a helpful message instead of StackOverflowError; tests should go in src/test/java/com/ysj/CircularDependencyTest.java.
  • Extend XmlBeanDefinitionReader to support constructor injection: Add parsing for <constructor-arg> tags parallel to existing <property> logic in parsePropertyValues(), then add AutowireCapableBeanFactory.instantiateBean() overload that accepts constructor arguments and uses reflection to invoke matching constructors.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 2e0a2ba — Merge branch 'master' of github.com:code4craft/tiny-spring (code4craft)
  • 642a173 — 推广 (code4craft)
  • 24493cd — Merge pull request #6 from yusijia/master (code4craft)
  • 14ee2f2 — 一些总结 (yusijia)
  • 5d48d73 — Merge pull request #5 from yusijia/master (code4craft)
  • 8bf3714 — tiny-spring详细分析 (yusijia)
  • 852d12a — Merge pull request #3 from dugu9sword/master (code4craft)
  • 0869f19 — 加入一点分析 (dugu9sword)
  • 93201bc — 加入一点分析 (dugu9sword)
  • f382144 — Merge pull request #1 from bitdeli-chef/master (code4craft)

🔒Security observations

  • High · Outdated Dependency: cglib-nodep 2.1_3 — pom.xml - cglib-nodep dependency. The project uses cglib-nodep version 2.1_3, which is extremely outdated (released around 2009). This version contains known security vulnerabilities and lacks modern security patches. cglib is used for dynamic proxy generation in AOP functionality. Fix: Update to the latest stable version of cglib (3.3.0 or newer). Verify compatibility with the current codebase and run full test suite after upgrade.
  • High · Outdated Dependency: aspectjweaver 1.6.11 — pom.xml - aspectjweaver dependency. The project uses AspectJ Weaver version 1.6.11, released around 2011. This version is severely outdated and may contain multiple known CVEs. AspectJ is used for AOP pointcut expression matching, making this a critical component. Fix: Upgrade to the latest stable version of aspectjweaver (1.9.20 or newer). Review release notes for breaking changes and test thoroughly.
  • High · Outdated Dependency: JUnit 4.7 — pom.xml - junit dependency. The project uses JUnit 4.7 from 2010, which is severely outdated. While test-scoped, using outdated testing frameworks can mask security issues in code. Fix: Upgrade to JUnit 4.13 (latest 4.x) or migrate to JUnit 5.x for modern testing capabilities and security patches.
  • Medium · Outdated Dependency: aopalliance 1.0 — pom.xml - aopalliance dependency. The aopalliance library version 1.0 is from 2003 and is no longer actively maintained. While this is a minimal interface library, it should be reviewed for any potential issues. Fix: Verify if aopalliance 1.0 is the latest available version. Consider if this dependency is still necessary or if it's bundled with other dependencies like Spring.
  • Medium · Unsafe Reflection in Bean Factory — src/main/java/com/ysj/tinySpring/beans/factory/AbstractBeanFactory.java and AutowireCapableBeanFactory.java. The codebase implements a custom IoC container using reflection for bean instantiation and property injection. While common in Spring-like frameworks, improper reflection usage could allow instantiation of arbitrary classes if bean definitions are not properly validated. Fix: Implement strict validation of bean class names from XML configuration. Use a whitelist approach for allowed classes. Never deserialize untrusted XML bean definitions without validation.
  • Medium · XML External Entity (XXE) Injection Risk — src/main/java/com/ysj/tinySpring/beans/xml/XmlBeanDefinitionReader.java. The XmlBeanDefinitionReader parses XML configuration files. If the XML parser is not configured to disable XXE attacks, it could be vulnerable to XXE injection, allowing attackers to read arbitrary files or perform denial-of-service attacks. Fix: Ensure XML parser is configured to disable DOCTYPE declarations, external entity resolution, and external DTDs. Verify SAXParserFactory or DocumentBuilderFactory has XXE protections enabled.
  • Low · Incomplete Build Configuration — pom.xml - build section. The pom.xml file appears to be truncated (ends with '<build><plugins><'). This may indicate incomplete configuration and makes it difficult to verify all security settings like plugin versions and compiler configuration. Fix: Complete the pom.xml configuration. Specify Java source/target version (1.8 or higher). Add maven-compiler-plugin configuration. Consider adding maven-shade-plugin or maven-assembly-plugin versions.
  • Low · Missing HTTPS in URL — pom.xml - url field and schema namespace. The project URL in pom.xml points to an old HTTP URL (http://maven.apache.org/...). While not a direct vulnerability, using HTTP for Maven Central or project documentation is outdated practice. Fix: Update to HTTPS URLs: https://maven.apache.org/. Ensure Maven is configured to use HTTPS for repository access.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · code4craft/tiny-spring — RepoPilot