Small Spring系列七:annotation Injection(三)

栏目: Java · 发布时间: 6年前

内容简介:秋水共长天一色 落霞与孤鹜齐飞。前两章我们已经完成了使用

秋水共长天一色 落霞与孤鹜齐飞。

Small Spring系列七:annotation Injection(三)

概述

前两章我们已经完成了使用 ASM 读取 Annotation 、新增 SimpleMetadataReader 封装了复杂的 Vister 、同时引入了 AnnotatedBeanDefinitionScannedGenericBeanDefinition 表明注解扫描的 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) 方法,如果 typeAccountDao 则找到(或创建)对应的实例并且返回。

这么一看,貌似是可行的,但我们在使用 Spring@Autowired 注解时发现,该注解可以应用于构造器注入、属性注入和 setter 注入。 spring 提供了一个 DependencyDescriptor 来封装 @Autowired 所有情况。

再有我们确定要把 resolveDependency 方法放置到 BeanFactory 中吗? BeanFactory 是我们的一个顶级接口,我们不希望对外暴露太多的方法,所以我们新增一个 AutowireCapableBeanFactory 接口,在 AutowireCapableBeanFactory 中增加 resolveDependency 方法。 AutowireCapableBeanFactory 继承 BeanFactory

DependencyDescriptor

封装 @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;
    }
}

AutowireCapableBeanFactory

增加 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);
}

DefaultBeanFactory

由实现 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());
            }
        }
    }

......

}

GenericBeanDefinition

新增 beanClass 属性,缓存 beanclass 对象

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;
    }

}

DependencyDescriptorTest

测试 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);

    }
}

代码下载

Field Injection

上面我们已经可以通过 class 类型来获取 bean 的实例了,那么怎么才能实现自动注入呢?

首先我们需要一个类含有 targetClass 和一个集合的属性列表 List<Class> ,每个集合中的元素调用各自的 inject(taget) 方法(反射)从而实现属性注入。类图如下:

Small Spring系列七:annotation Injection(三)

InjectionElement

抽象类,表明需要注入的属性字段

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);
}

AutowiredFieldElement

继承抽象类 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);
        }
    }
}

InjectionMetadata

targetClassList<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);
        }
    }
}

InjectionMetadataTest

测试属性注入

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);
    }
}

代码下载

自动构建InjectionMetadata

以上我们只是通过手动的将 NioCoderService 转变成了 InjectionMetadata 并且调用 inject 方法,从而实现了 Field Injection ,我们需要一个类来自动帮我们处理这些操作。

AutowiredAnnotationBeanPostProcessor

用于自动构建 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;
    }
}

AutowiredAnnotationProcessorTest

测试 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

至此我们已经完成了 Field Injection 90%的工作,剩下要考虑的就是应该在什么时候调用类的这些方法?

所以我们要考虑一下 bean 的生命周期,关于 bean 的生命周期,可以看下图

Small Spring系列七:annotation Injection(三)

参考 Bean的生命周期

我们需要找 InstantiationAwareBeanPostProcessor.postProcessPropertyValues() 实现 Autowired 注解。关于 BeanPostProcessor 的类图如下:

Small Spring系列七:annotation Injection(三)

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;
    }
}

InstantiationAwareBeanPostProcessor

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 {
    }

}

AutowiredAnnotationBeanPostProcessor

实现 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

新增 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

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;
    }
}

AbstractApplicationContext

构造方法时注册 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);
    }
}

ApplicationContextTestV4

测试注解注入

/**
 *
 */
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


以上所述就是小编给大家介绍的《Small Spring系列七:annotation Injection(三)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

What Technology Wants

What Technology Wants

Kevin Kelly / Penguin Group (USA) Incorporated / 2010-10-14 / USD 27.95

A refreshing view of technology as a living force in the world. This provocative book introduces a brand-new view of technology. It suggests that technology as a whole is not a jumble of wires and ......一起来看看 《What Technology Wants》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具