Trong bài viết trước về bean autowiring sử dụng @Autowired annotation, mình có đề cập đến đối tượng AutowiredAnnotationBeanPostProcessor được sử dụng để tự động đưa đối tượng phụ thuộc vào đối tượng bị phụ thuộc. Chắc một số bạn cũng thắc mắc là đối tượng này làm thế nào để làm được điều đó phải ko nhỉ? Mình cũng vậy, và đó là lý do mình đã lướt qua code của class AutowiredAnnotationBeanPostProcessor để xem đối tượng này thực sự đã làm những gì?
OK, đầu tiên mình đọc constructor của nó, nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * Create a new AutowiredAnnotationBeanPostProcessor * for Spring's standard {@link Autowired} annotation. * <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available. */ @SuppressWarnings("unchecked") public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); try { this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. } } |
Ở đây, các bạn thấy, class này có một biến tên là autowiredAnnotationTypes chứa thông tin của ba class là Autowired.class, Value.class và Inject.class. Nó là biến kiểu Set các bạn ạ:
1 |
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(); |
và biến này được sử dụng trong 3 phương thức khác nhau nhằm mục đích xử lý cho 3 annotation là @Autowired, @Value và @Inject.
Hãy xem đó là ba phương thức nào nhé các bạn:
1 2 3 4 5 6 7 |
@Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { if (beanType != null) { InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); metadata.checkConfigMembers(beanDefinition); } } |
Phương thức này dùng cho @Autowired annotation.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; } |
Phương thức này dùng cho @Value annotation. Công dụng của annotation này mình sẽ nói trong những bài sau nhé các bạn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * 'Native' processing method for direct calls with an arbitrary target instance, * resolving all of its fields and methods which are annotated with {@code @Autowired}. * @param bean the target instance to process * @throws BeansException if autowiring failed */ public void processInjection(Object bean) throws BeansException { Class<?> clazz = bean.getClass(); InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null); try { metadata.inject(bean, null, null); } catch (Throwable ex) { throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex); } } |
Phương thức này dùng cho @Inject annotation nhé các bạn. Công dụng của annotation mình cũng sẽ đề cập trong những bài viết sau.
Điểm chung của ba phương thức trên là nó gọi tới một phương thức khác có tên gọi là findAutowiringMetadata. Và trong phương thức này có phương thức buildAutowiringMetadata, đọc phương thức buildAutowiringMetadata bạn sẽ hình dung đối tượng AutowiredAnnotationBeanPostProcessor đã làm gì để xử lý trong các trường hợp bạn khai báo @Autowired annotation ở biến, ở method và ở constructor. Tương tự cho @Value annotation và @Inject annotation.
Xem qua hai phương thức mình vừa nói nhé các bạn.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } try { metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } catch (NoClassDefFoundError err) { throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + "] for autowiring metadata: could not find class that it depends on", err); } } } } return metadata; } |
Và
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>(); Class<?> targetClass = clazz; do { final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>(); ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; } boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } } }); ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterTypes().length == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); } |
Mình nghĩ các bạn có thể đọc hiểu những đoạn code này, có vấn đề gì cứ hỏi mình nhé.
giặc núi
dạo này anh bận hay sao mà thấy lâu quá mục spring ko thấy anh ra bài mới nhỉ. hóng
Khanh Nguyễn
Anh mới viết bài về IoC đó em, http://huongdanjava.com/inversion-control-va-dependency-injection.html