- Bước 1: Dùng Reflection quét package của file Main để tìm ra toàn bộ các class được khai báo trong package, đưa vào 1 HashSet.
- Bước 2: Tạo annotation @Instance, chạy vòng lặp: những class nào có đánh dấu @Instance thì khởi tạo instance cho nó, lưu vào 1 HashMap
, Object>. - Bước 3: Tạo annotation @Inject, và tiếp tục lặp qua HashMap ở bước 2, nếu instance nào mà có các field được đánh dấu @Inject thì gắn object đã được tạo trong HashMap(bước 2) vào field đó.
Cách nhúng đối tượng tương tự như @Autowired của Spring boot?
Đặt vấn đề:
Lúc đọc cuốn "Những Nguyên Tắc Sống Còn Trong Lập Trình" của anh Tạ Văn Dũng, em có khá ấn tượng về cách anh giải thích về ý tưởng Inversion-of-control. Sau đó, em cũng vọc vạch làm thử 1 cái tương tự, đại ý là em làm như này:
Remain: 5
2 Answers
toilahtc
Beginner
toilahtc
Beginner
Trong trường hợp này, bạn phải cung cấp các annotation để làm rõ thêm rằng bean nào sẽ được chỉ định cho interface này bằng cách cung cấp các annotation như
@Qualifier
hoặc @Primary
(vui lòng tìm hiểu thêm trên internet nếu chưa rõ về 2 bean này) và như vậy thì spring container sẽ có thể hiểu và inject đúng bean cho bạn.-
1
tvd12
Beginner
tvd12
Beginner
Sorry em, anh reply chậm. Để có thể inject ở dạng interface thì em phải lưu map cả lớp cài đặt lẫn interface với cái bean em ạ, ví dụ:
public interface Ruler {}
và lớp cài đặt là:
public interface RulerImpl implements Ruler {}
Thì code DI của em có thể thế này:
@Retention(RetentionPolicy.RUNTIME) @interface Instant {} @Retention(RetentionPolicy.RUNTIME) @interface Inject {} class BeanManagement { public static void main(String[] args) throws Exception { EzyReflection reflections = new EzyReflectionProxy( "org.youngmonkeys.di" ); Set<Class<?>> classes = reflections.getAnnotatedClasses(Instant.class); Map<String, Object> beanByName = new HashMap<>(); Map<Class<?>, Object> beanByType = new HashMap<>(); for (Class<?> clazz : classes) { Object bean = clazz .getDeclaredConstructor() .newInstance(); beanByName.put(EzyClasses.getVariableName(clazz), bean); Class<?> parentClass = clazz; while (parentClass != null) { beanByType.put(parentClass, bean); parentClass = parentClass.getSuperclass(); } for (Class<?> inf : clazz.getInterfaces()) { beanByType.put(inf, bean); } injectDependenciesToBean(beanByName, beanByType, bean); } } public static void injectDependenciesToBean( Map<String, Object> beanByName, Map<Class<?>, Object> beanByType, Object bean ) throws Exception { Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Inject.class)) { // lấy phụ thuộc từ name trước, nếu không có thì lấy theo type Object dependency = beanByName.get( EzyClasses.getVariableName(field.getType()) ); if (dependency == null) { Class<?> parentClass = field.getType(); while (parentClass != null && dependency == null) { dependency = beanByType.get( parentClass ); parentClass = parentClass.getSuperclass(); } for (Class<?> inf : field.getType().getInterfaces()) { dependency = beanByType.get( inf ); if (dependency != null) { break; } } } field.setAccessible(true); field.set(bean, dependency); } } } }
Theo cách này thì việc lấy ra bean nào sẽ phụ thuộc vào tên bean trước, sau đó đến type. Nếu giả sử có nhiều lớp cài đặt 1 interface thì có lẽ em nên đặt tên cho khớp để lấy ra được bean phù hợp em ạ.
-
2