Created
December 29, 2025 14:32
-
-
Save ozanaaslan/98c22738b91ef407a9784f2b3c7c5be1 to your computer and use it in GitHub Desktop.
Minimalist IoC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import lombok.Getter; | |
| import java.lang.annotation.ElementType; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.lang.annotation.Target; | |
| import java.lang.reflect.Field; | |
| import java.lang.reflect.Method; | |
| import java.util.Map; | |
| import java.util.Optional; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| public class ServiceManager { | |
| @Getter private static final ServiceManager instance = new ServiceManager(); | |
| private final Map<Class<?>, Object> services = new ConcurrentHashMap<>(); | |
| private ServiceManager() {} | |
| /** | |
| * Scans an object for @ServiceBean annotations on methods and fields. | |
| * Methods are executed once, and their return value is registered as a service. | |
| */ | |
| public void registerBeans(Object provider) { | |
| // 1. Process Methods (Factory Methods) | |
| for (Method method : provider.getClass().getDeclaredMethods()) { | |
| if (method.isAnnotationPresent(ServiceBean.class)) { | |
| try { | |
| method.setAccessible(true); | |
| Object bean = method.invoke(provider); | |
| if (bean != null) { | |
| // Register using the return type as the key | |
| register((Class<Object>) method.getReturnType(), bean); | |
| } | |
| } catch (Exception e) { | |
| System.err.println("Failed to register bean from method: " + method.getName()); | |
| e.printStackTrace(); | |
| } | |
| } | |
| } | |
| // 2. Process Fields | |
| for (Field field : provider.getClass().getDeclaredFields()) { | |
| if (field.isAnnotationPresent(ServiceBean.class)) { | |
| try { | |
| field.setAccessible(true); | |
| Object bean = field.get(provider); | |
| if (bean != null) { | |
| register((Class<Object>) field.getType(), bean); | |
| } | |
| } catch (Exception e) { | |
| System.err.println("Failed to register bean from field: " + field.getName()); | |
| } | |
| } | |
| } | |
| } | |
| public <T> void register(Class<T> serviceInterface, T implementation) { | |
| services.put(serviceInterface, implementation); | |
| } | |
| public <T> Optional<T> getService(Class<T> serviceInterface) { | |
| return Optional.ofNullable(serviceInterface.cast(services.get(serviceInterface))); | |
| } | |
| public void inject(Object target) { | |
| for (Field field : target.getClass().getDeclaredFields()) { | |
| if (field.isAnnotationPresent(InjectService.class)) { | |
| field.setAccessible(true); | |
| getService(field.getType()).ifPresent(service -> { | |
| try { | |
| field.set(target, service); | |
| } catch (IllegalAccessException e) { | |
| e.printStackTrace(); | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| // --- Annotations --- | |
| @Retention(RetentionPolicy.RUNTIME) | |
| @Target({ElementType.METHOD, ElementType.FIELD}) | |
| public @interface ServiceBean {} | |
| @Retention(RetentionPolicy.RUNTIME) | |
| @Target(ElementType.FIELD) | |
| public @interface InjectService {} | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment