implement lightweight IOC/DI framework

- Add annotation system (@Component, @Service, @Configuration, @Bean, @Inject, @Qualifier, @Primary, @Scope, @PostConstruct, @Import, @TimiInjectApplication)
- Implement BeanContext for managing bean instances and definitions
- Implement BeanScanner for component scanning (file system and jar)
- Implement BeanFactory with constructor injection and lifecycle support
- Support @Configuration and @Bean factory methods
- Support @Qualifier and @Primary for multi-implementation
- Support @Scope (singleton/prototype)
- Support @PostConstruct lifecycle callback
- Support @Import and Module extension
- Add circular dependency detection
- Add dependency graph export
- Add demo and test cases

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Timi
2026-01-11 12:26:14 +08:00
parent 05606eda74
commit 71be7c07c0
43 changed files with 1429 additions and 1129 deletions

View File

@ -0,0 +1,17 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.annotation.Component;
/**
* 默认存储实现
*
* @author 夜雨
*/
@Component
public class DefaultStorage implements Storage {
@Override
public void save(String data) {
System.out.println("Default save: " + data);
}
}

View File

@ -0,0 +1,29 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.TimiInjectApplication;
/**
* 演示应用
*
* @author 夜雨
*/
@TimiInjectApplication("com.imyeyu.inject.demo")
public class DemoApp {
public static void main(String[] args) {
TimiInject inject = TimiInject.run(DemoApp.class);
UserService userService = inject.di(UserService.class);
System.out.println(userService.hello());
String appName = inject.di("appName", String.class);
System.out.println("App Name: " + appName);
Storage storage = inject.di(Storage.class);
System.out.println("Storage: " + storage.getClass().getSimpleName());
System.out.println("\n=== Dependency Graph ===");
System.out.println(inject.exportDependencyGraph());
}
}

View File

@ -0,0 +1,23 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.annotation.Bean;
import com.imyeyu.inject.annotation.Configuration;
/**
* 演示配置
*
* @author 夜雨
*/
@Configuration
public class DemoConfig {
@Bean("appName")
public String appName() {
return "timi-inject-demo";
}
@Bean
public Integer serverPort() {
return 8080;
}
}

View File

@ -0,0 +1,19 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.Primary;
/**
* 快速存储实现
*
* @author 夜雨
*/
@Component
@Primary
public class FastStorage implements Storage {
@Override
public void save(String data) {
System.out.println("Fast save: " + data);
}
}

View File

@ -0,0 +1,67 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.TimiInject;
import com.imyeyu.inject.annotation.Component;
import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.Service;
import com.imyeyu.inject.annotation.TimiInjectApplication;
/**
* 快速测试
*
* @author 夜雨
*/
public class QuickTest {
@TimiInjectApplication("com.imyeyu.inject.demo")
public static class TestApp {
}
@Service
public static class TestService {
private boolean initialized = false;
@PostConstruct
public void init() {
this.initialized = true;
System.out.println("TestService initialized");
}
public boolean isInitialized() {
return initialized;
}
}
public static void main(String[] args) {
System.out.println("=== Timi-Inject Quick Test ===\n");
TimiInject inject = TimiInject.run(TestApp.class);
System.out.println("\n=== Test 1: Simple DI ===");
UserRepository repo = inject.di(UserRepository.class);
System.out.println("UserRepository: " + (repo != null ? "OK" : "FAIL"));
System.out.println("\n=== Test 2: Constructor Injection ===");
UserService service = inject.di(UserService.class);
System.out.println("UserService: " + service.hello());
System.out.println("\n=== Test 3: @Bean Method ===");
String appName = inject.di("appName", String.class);
System.out.println("AppName: " + appName);
Integer port = inject.di("serverPort", Integer.class);
System.out.println("ServerPort: " + port);
System.out.println("\n=== Test 4: @Primary ===");
Storage storage = inject.di(Storage.class);
System.out.println("Storage type: " + storage.getClass().getSimpleName());
System.out.println("Expected FastStorage: " + (storage instanceof FastStorage ? "OK" : "FAIL"));
System.out.println("\n=== Test 5: Manual Registration ===");
inject.ioc("customBean", "Custom Value");
String custom = inject.di("customBean", String.class);
System.out.println("Custom bean: " + custom);
System.out.println("\n=== All Tests Passed! ===");
}
}

View File

@ -0,0 +1,10 @@
package com.imyeyu.inject.demo;
/**
* 存储接口
*
* @author 夜雨
*/
public interface Storage {
void save(String data);
}

View File

@ -0,0 +1,16 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.annotation.Resources;
/**
* 用户仓储
*
* @author 夜雨
*/
@Resources
public class UserRepository {
public UserRepository() {
System.out.println("UserRepository created");
}
}

View File

@ -0,0 +1,28 @@
package com.imyeyu.inject.demo;
import com.imyeyu.inject.annotation.PostConstruct;
import com.imyeyu.inject.annotation.Service;
/**
* 用户服务
*
* @author 夜雨
*/
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
@PostConstruct
public void init() {
System.out.println("UserService initialized");
}
public String hello() {
return "Hello from UserService! Repository: " + repository.getClass().getSimpleName();
}
}