秋水共长天一色 落霞与孤鹜齐飞。
前两章我们已经完成了使用 ASM
读取 Annotation
、新增 SimpleMetadataReader
封装了复杂的 Vister
、同时引入了 AnnotatedBeanDefinition
和 ScannedGenericBeanDefinition
表明注解扫描的 BeanDefinition
。本章我们来实现最后的 Field Injection
。
@Component(value = "nioCoder") public class NioCoderService { @Autowired private AccountDao accountDao; @Autowired private ItemDao itemDao; }
要实现 Field Injection
我们需要根据 class
类型从 BeanFactory
中获取一个对象然后注入。即需要在 BeanFactory
新增一个 BeanFactory.resolveDepency(Class type)
方法,如果 type
为 AccountDao
则找到(或创建)对应的实例并且返回。
这么一看,貌似是可行的,但我们在使用 Spring
的 @Autowired
注解时发现,该注解可以应用于构造器注入、属性注入和 setter
注入。 spring
提供了一个 DependencyDescriptor
来封装 @Autowired
所有情况。
再有我们确定要把 resolveDependency
方法放置到 BeanFactory
中吗? BeanFactory
是我们的一个顶级接口,我们不希望对外暴露太多的方法,所以我们新增一个 AutowireCapableBeanFactory
接口,在 AutowireCapableBeanFactory
中增加 resolveDependency
方法。 AutowireCapableBeanFactory
继承 BeanFactory
。
封装 @Autowired
所有情况。(暂只支持字段注入,不支持方法注入)
package com.niocoder.beans.factory.config; import java.lang.reflect.Field; /** * 表明属性注入或者方法注入 * * @author zhenglongfei */ public class DependencyDescriptor { /** * 属性注入 */ private Field field; /** * 方法注入 */ // private MethodParameter methodParameter; private boolean required; public DependencyDescriptor(Field field, boolean required) { this.field = field; this.required = required; } public Class<?> getDependencyType() { if (this.field != null) { // 字段的类型如 AccountDao ItemDao return field.getType(); } // TODO 方法注入不支持 throw new RuntimeException("only support field dependency"); } public boolean isRequired() { return this.required; } }
增加 resolveDependency(DependencyDescriptor descriptor)
方法,根据 field
返回对应的实例。
package com.niocoder.beans.factory.config; import com.niocoder.beans.factory.BeanFactory; /** * 表明注解 注入的beanFactory */ public interface AutowireCapableBeanFactory extends BeanFactory { /** * 根据字段属性的描述,获得所对应的实例 * * @param descriptor * @return */ Object resolveDependency(DependencyDescriptor descriptor); }
由实现 BeanFactory
改成实现 AutowireCapableBeanFactory
。
public class DefaultBeanFactory extends DefaultSingletonBeanRegistry implements AutowireCapableBeanFactory, BeanDefinitionRegistry { ...... @Override public Object resolveDependency(DependencyDescriptor descriptor) { Class<?> typeToMatch = descriptor.getDependencyType(); for (BeanDefinition bd : this.beanDefinitionMap.values()) { // 确保BeanDefinition 有Class对象,而不是class的字符串 resolveBeanClass(bd); Class<?> beanClass = bd.getBeanClass(); if (typeToMatch.isAssignableFrom(beanClass)) { return this.getBean(bd.getId()); } } return null; } public void resolveBeanClass(BeanDefinition bd) { if (bd.hasBeanClass()) { return; } else { try { bd.resolveBeanClass(ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException e) { throw new RuntimeException("can't load class" + bd.getBeanClassName()); } } } ...... }
新增 beanClass
属性,缓存 bean
的 class
对象
public class GenericBeanDefinition implements BeanDefinition { private Class<?> beanClass; ...... @Override public Class<?> getBeanClass() { if (this.beanClass == null) { throw new IllegalStateException("Bean class name [" + this.getBeanClassName() + "] has not been resolve into an actual Class"); } return this.beanClass; } @Override public boolean hasBeanClass() { return this.beanClass != null; } @Override public Class<?> resolveBeanClass(ClassLoader beanClassLoader) throws ClassNotFoundException { String className = getBeanClassName(); if (className == null) { return null; } Class<?> resolvedClass = beanClassLoader.loadClass(className); this.beanClass = resolvedClass; return resolvedClass; } }
测试 DependencyDescriptor
/** * 测试DependencyDescriptor */ public class DependencyDescriptorTest { @Test public void testResolveDependency() throws Exception { DefaultBeanFactory factory = new DefaultBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinition(new ClassPathResource("bean-v4.xml")); Field f = NioCoderService.class.getDeclaredField("accountDao"); DependencyDescriptor descriptor = new DependencyDescriptor(f, true); Object o = factory.resolveDependency(descriptor); Assert.assertTrue(o instanceof AccountDao); } }
上面我们已经可以通过 class
类型来获取 bean
的实例了,那么怎么才能实现自动注入呢?
首先我们需要一个类含有 targetClass
和一个集合的属性列表 List<Class>
,每个集合中的元素调用各自的 inject(taget)
方法(反射)从而实现属性注入。类图如下:
抽象类,表明需要注入的属性字段
package com.niocoder.beans.factory.annotation; import com.niocoder.beans.factory.config.AutowireCapableBeanFactory; import java.lang.reflect.Member; /** * @author zhenglongfei */ public abstract class InjectionElement { protected Member member; protected AutowireCapableBeanFactory factory; InjectionElement(Member member, AutowireCapableBeanFactory factory) { this.member = member; this.factory = factory; } /** * 属性注入的抽象方法 * * @param target */ public abstract void inject(Object target); }
继承抽象类 InjectionElement
实现属性注入
package com.niocoder.beans.factory.annotation; import com.niocoder.beans.factory.BeanCreationException; import com.niocoder.beans.factory.config.AutowireCapableBeanFactory; import com.niocoder.beans.factory.config.DependencyDescriptor; import com.niocoder.util.*; import java.lang.reflect.Field; /** * @author zhenglongfei */ public class AutowiredFieldElement extends InjectionElement { boolean required; public AutowiredFieldElement(Field f, boolean required, AutowireCapableBeanFactory factory) { super(f, factory); this.required = required; } public Field getField() { return (Field) this.member; } @Override public void inject(Object target) { Field field = this.getField(); try { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); Object value = factory.resolveDependency(desc); if (value != null) { ReflectionUtils.makeAccessible(field); field.set(target, value); } } catch (Throwable e) { throw new BeanCreationException("could not autowire field " + field, e); } } }
将 targetClass
和 List<InjectionElement>
结合,从而实现属性注入
package com.niocoder.beans.factory.annotation; import java.util.List; /** * @author zhenglongfei */ public class InjectionMetadata { private final Class<?> targetClass; private List<InjectionElement> injectionElements; public InjectionMetadata(Class<?> targetClass, List<InjectionElement> injectionElements) { this.targetClass = targetClass; this.injectionElements = injectionElements; } public List<InjectionElement> getInjectionElements() { return injectionElements; } public void inject(Object target) { if (injectionElements == null || injectionElements.isEmpty()) { return; } for (InjectionElement ele : injectionElements) { ele.inject(target); } } }
测试属性注入
package com.niocoder.test.v4; import com.niocoder.beans.factory.annotation.AutowiredFieldElement; import com.niocoder.beans.factory.annotation.InjectionElement; import com.niocoder.beans.factory.annotation.InjectionMetadata; import com.niocoder.beans.factory.support.DefaultBeanFactory; import com.niocoder.beans.factory.xml.XmlBeanDefinitionReader; import com.niocoder.core.io.ClassPathResource; import com.niocoder.dao.v4.AccountDao; import com.niocoder.dao.v4.ItemDao; import com.niocoder.service.v4.NioCoderService; import org.junit.Assert; import org.junit.Test; import java.lang.reflect.Field; import java.util.LinkedList; public class InjectionMetadataTest { @Test public void testInjection() throws Exception { DefaultBeanFactory factory = new DefaultBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinition(new ClassPathResource("bean-v4.xml")); Class<?> clz = NioCoderService.class; LinkedList<InjectionElement> elements = new LinkedList<InjectionElement>(); { Field f = NioCoderService.class.getDeclaredField("accountDao"); InjectionElement injectionElement = new AutowiredFieldElement(f, true, factory); elements.add(injectionElement); } { Field f = NioCoderService.class.getDeclaredField("itemDao"); InjectionElement injectionElement = new AutowiredFieldElement(f, true, factory); elements.add(injectionElement); } InjectionMetadata metadata = new InjectionMetadata(clz, elements); NioCoderService nioCoderService = new NioCoderService(); metadata.inject(nioCoderService); Assert.assertTrue(nioCoderService.getAccountDao() instanceof AccountDao); Assert.assertTrue(nioCoderService.getItemDao() instanceof ItemDao); } }
以上我们只是通过手动的将 NioCoderService
转变成了 InjectionMetadata
并且调用 inject
方法,从而实现了 Field Injection
,我们需要一个类来自动帮我们处理这些操作。
用于自动构建 InjectionMetadata
public class AutowiredAnnotationBeanPostProcessor{ private AutowireCapableBeanFactory beanFactory; private String requiredParameterName = "required"; private boolean requiredParameterValue = true; /** * 存储需要判断的注解信息 */ private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(); /** * 添加Autowired注解 */ public AutowiredAnnotationBeanPostProcessor() { this.autowiredAnnotationTypes.add(Autowired.class); } /** * 给定class对象构建InjectionMetadata * @param clazz * @return */ public InjectionMetadata buildAutowiringMetadata(Class<?> clazz) { List<InjectionElement> elements = new LinkedList<>(); Class<?> targetClass = clazz; do { List<InjectionElement> currElements = new LinkedList<>(); for (Field field : targetClass.getDeclaredFields()) { Annotation ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { continue; } boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required, beanFactory)); } } for (Method method : targetClass.getDeclaredMethods()) { //TODO } elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements); } /** * 判断是否是required是否必须 * * @param ann * @return */ private boolean determineRequiredStatus(Annotation ann) { try { Method method = ReflectionUtils.findMethod(ann.annotationType(), this.requiredParameterName); if (method == null) { // Annotations like @Inject and @Value don't have a method (attribute) named "required" // -> default to required status return true; } return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, ann)); } catch (Exception ex) { // An exception was thrown during reflective invocation of the required attribute // -> default to required status return true; } } /** * 判断属性是否存在Autowired 注解 * * @param field * @return */ private Annotation findAutowiredAnnotation(Field field) { for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { Annotation ann = AnnotationUtils.getAnnotation(field, type); if (ann != null) { return ann; } } return null; } public void setBeanFactory(ConfigurableBeanFactory beanFactory) { this.beanFactory = beanFactory; } }
测试 AutowiredAnnotationProcessor
public class AutowiredAnnotationProcessorTest { AccountDao accountDao = new AccountDao(); ItemDao itemDao = new ItemDao(); DefaultBeanFactory beanFactory = new DefaultBeanFactory() { @Override public Object resolveDependency(DependencyDescriptor descriptor) { if (descriptor.getDependencyType().equals(AccountDao.class)) { return accountDao; } if (descriptor.getDependencyType().equals(ItemDao.class)) { return itemDao; } throw new RuntimeException("can't support types except AccountDao and ItemDao"); } }; @Test public void testGetInjectionMetadata() { AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(beanFactory); InjectionMetadata injectionMetadata = processor.buildAutowiringMetadata(NioCoderService.class); List<InjectionElement> elements = injectionMetadata.getInjectionElements(); Assert.assertEquals(2, elements.size()); assertFieldExists(elements,"accountDao"); assertFieldExists(elements,"itemDao"); NioCoderService nioCoderService = new NioCoderService(); injectionMetadata.inject(nioCoderService); Assert.assertTrue(nioCoderService.getAccountDao() instanceof AccountDao); Assert.assertTrue(nioCoderService.getItemDao() instanceof ItemDao); } private void assertFieldExists(List<InjectionElement> elements, String fieldName) { for (InjectionElement ele : elements) { AutowiredFieldElement fieldElement = (AutowiredFieldElement) ele; Field field = fieldElement.getField(); if (field.getName().equals(fieldName)) { return; } } Assert.fail(fieldName + "does not exist!"); } }
至此我们已经完成了 Field Injection
90%的工作,剩下要考虑的就是应该在什么时候调用类的这些方法?
所以我们要考虑一下 bean
的生命周期,关于 bean
的生命周期,可以看下图
参考 Bean的生命周期
我们需要找 InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
实现 Autowired
注解。关于 BeanPostProcessor
的类图如下:
bean
初始化之前和初始化之后的处理器操作
package com.niocoder.beans.factory.config; import com.niocoder.beans.BeansException; /** * bean的后置处理器 * * @author zhenglongfei */ public interface BeanPostProcessor { /** * 初始化之前的操作 * * @param bean * @param beanName * @return * @throws BeansException */ default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * 初始化之后的操作 * * @param bean * @param beanName * @return * @throws BeansException */ default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
bean
实例化之前和实例化之后的处理器操作
package com.niocoder.beans.factory.config; import com.niocoder.beans.BeansException; /** * 实例化的后处理器 * * @author zhenglongfei */ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { /** * 实例化之前 * * @param beanClass * @param beanName * @return * @throws BeansException */ default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } /** * 实例化之后 * * @param bean * @param beanName * @return * @throws BeansException */ default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } /** * @param bean * @param beanName * @throws BeansException */ default void postProcessPropertyValues(Object bean, String beanName) throws BeansException { } }
实现 InstantiationAwareBeanPostProcessor
,在 postProcessPropertyValues
方法实现属性注入
/** * 注解注入的后处理器 * * @author zhenglongfei */ public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor { ...... @Override public void postProcessPropertyValues(Object bean, String beanName) throws BeansException { InjectionMetadata metadata = buildAutowiringMetadata(bean.getClass()); try { metadata.inject(bean); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } } }
新增 ConfigurableBeanFactory
来处理 BeanPostProcessor
package com.niocoder.beans.factory.config; import java.util.List; /** * 可配置的beanFactory * * @author zhenglongfei */ public interface ConfigurableBeanFactory extends AutowireCapableBeanFactory { /** * 增加BeanPostProcessor * * @param postProcessor */ void addBeanPostProcessor(BeanPostProcessor postProcessor); /** * 获取 BeanPostProcessor * * @return */ List<BeanPostProcessor> getBeanPostProcessors(); }
DefaultBeanFactory
从实现 AutowireCapableBeanFactory
修改为 ConfigurableBeanFactory
,增加 beanPostProcessors
属性, 在 populateBean
方法时处理 BeanPostProcessor
。
/** * BeanFactory的默认实现类 * * @author zhenglongfei */ public class DefaultBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory, BeanDefinitionRegistry { /** * 存放BeanPostProcessor */ private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>(); private void populateBean(BeanDefinition bd, Object bean) { for (BeanPostProcessor postProcessor : this.getBeanPostProcessors()) { if (postProcessor instanceof InstantiationAwareBeanPostProcessor) { ((InstantiationAwareBeanPostProcessor) postProcessor).postProcessPropertyValues(bean, bd.getId()); } } ...... } @Override public void addBeanPostProcessor(BeanPostProcessor postProcessor) { this.beanPostProcessors.add(postProcessor); } @Override public List<BeanPostProcessor> getBeanPostProcessors() { return this.beanPostProcessors; } }
构造方法时注册 AutowiredAnnotationBeanPostProcessor
实现注解注入
public abstract class AbstractApplicationContext implements ApplicationContext { private DefaultBeanFactory factory = null; public AbstractApplicationContext(String configFile) { factory = new DefaultBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); Resource resource = this.getResourceByPath(configFile); reader.loadBeanDefinition(resource); registerBeanPostProcessors(factory); } /** * 具体由子类实现 * * @param configFile * @return */ protected abstract Resource getResourceByPath(String configFile); @Override public Object getBean(String beanId) { return factory.getBean(beanId); } protected void registerBeanPostProcessors(ConfigurableBeanFactory beanFactory) { AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor(); processor.setBeanFactory(factory); beanFactory.addBeanPostProcessor(processor); } }
测试注解注入
/** * */ public class ApplicationContextTestV4 { @Test public void testGetBeanProperty() { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-v4.xml"); NioCoderService nioCoder = (NioCoderService) ctx.getBean("nioCoder"); Assert.assertNotNull(nioCoder.getAccountDao()); Assert.assertNotNull(nioCoder.getItemDao()); } }
从零开始造Spring