六、Spring源码分析--更强的反射工具

更强的反射工具

在spring中,我们除了能看到内省相关的api,看到的更多的可能是反射api了,当然针对原生api的复杂性,spring同样进行了封装,让其使用起来更简单。

spring给我们提供了强大的反射工具BeanWrapper,下边的例子展示了该类如何配合BeanDefinition对其进行了实例化:

1、bean的创建

@Test
public void testCreate() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // 1、通过任意形式捕获beanDefinition
    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClassName("com.ydlclass.User");
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue("name","lily");
    propertyValues.addPropertyValue("age",12);
    beanDefinition.setPropertyValues(propertyValues);

    // 2、通过权限定名称获得Class
    Class<?> aClass = Class.forName(beanDefinition.getBeanClassName());

    // 3、使用BeanWrapper包裹实例,使其更方便使用反射方法
    BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);
    beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());
    Object bean = beanWrapper.getWrappedInstance();
    logger.info("The bean is [{}]",bean);
}

我们可以看到BeanWrapperImpl仅仅需要一个Class就能十分友好的结合beanDefinition进行构建和赋值,而不需要通过复杂的反射获取构造器进行实例化,获取字段对象进行赋值,当然这仅仅是api封装的功劳,原理还是那些东西。

2、批量构造

我们可以使用如下的方法进行批量构造:

@Test
public void testBatchCreate() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // 1、通过任意形式捕获beanDefinition
    BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
    XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(registry);
    xmlReader.loadBeanDefinitions("classpath:spring.xml");


    // 2、通过反射实例化
    String[] definitionNames = registry.getBeanDefinitionNames();
    for (String definitionName : definitionNames) {
        BeanDefinition beanDefinition = registry.getBeanDefinition(definitionName);
        String beanClassName = beanDefinition.getBeanClassName();
        Class<?> aClass = Class.forName(beanClassName);
        Constructor<?> constructor = aClass.getConstructor();
        Object bean = constructor.newInstance();

        // 3、使用BeanWrapper包裹实例,使其更方便使用反射方法
        BeanWrapper beanWrapper = new BeanWrapperImpl(bean);
        beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());
        bean = beanWrapper.getWrappedInstance();
        System.out.println(bean);
    }
}

貌似事与愿违,此时抛出一个异常,是说无法将一个TypedStringValue类型的数据转化为一个Integer,没有合适的转化器:

org.springframework.beans.TypeMismatchException: Failed to convert property value of type ‘org.springframework.beans.factory.config.TypedStringValue’ to required type ‘java.lang.Integer’ for property ‘age’;

这个问题,我们先按下不表,后边再解释,接着我们看几个常用的类:

3、ResolvableType

该类可以封装Java类型,提供对超类类型、接口和泛型参数的访问,以及最终解析为类的能力,这是非常常见的一个类,他能及其方便的简化对反射api的调用,该类在spring中的使用率非常高。

ResolvableType可以从字段、方法参数、方法返回类型或类中获得。这个类上的大多数方法本身都会返回一个ResolvableType,以便于链式调用。

官方的案例如下:

private HashMap<Integer, List<String>> myMap;
public void example() {
    ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
    t.getSuperType(); // AbstractMap<Integer, List<String>>
    t.asMap(); // Map<Integer, List<String>>
    t.getGeneric(0).resolve(); // Integer  // 获取泛型
    t.getGeneric(1).resolve(); // List
    t.getGeneric(1); // List<String>
    //第二个泛型,里面的泛型,即List<String>里面的String
    t.resolveGeneric(1, 0); // String
}

我们也可以写测试用例测试一下:

@Test
public void testTypeResolvableType() throws NoSuchFieldException {
    ResolvableType type = ResolvableType.forField(DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects"));
    // 获取类型
    logger.info(type.getType().getTypeName());
    // 获取泛型
    logger.info(Arrays.toString(type.getGenerics()));
    logger.info(Arrays.toString(type.getInterfaces()));
    logger.info(Arrays.toString(type.resolveGenerics()));
    // 获取来源
    Class<?> resolve = type.resolve();
    logger.info(type.getRawClass().getName());
}

Resolvable:可解析的,可分解的。spring中经常出现这个单词。如ResolvableAttribute,ResolvableType,registerResolvableDependency,后期遇到我们再学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值