spring 源码阅读(基础)

您所在的位置:网站首页 反射大师源码 spring 源码阅读(基础)

spring 源码阅读(基础)

2023-03-16 03:15| 来源: 网络整理| 查看: 265

 1.内省api

1.什么是内省:

        内省是java语言针对bean属性,事件的一种缺省处理方法,spring源码中也经常会出现相关的api。

        javaBean是一种特殊的类,主要用于信息传递,这种类中的方法主要用于私有字段的访问,且方法名符合某种命名规则,事实上,内省机制也是通过反射来实现的。

        反射的功能是比内省强大的。

在Java内省中,用到的基本上就是上述几个类。

        内省api的一般的做法是通过类 Introspector 的 getBeanInfo方法来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的 取值/赋值 方法,然后我们就可以通过反射机制来调用这些方法,这就是内省机制。

import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; @Test public void testIntrospect1() throws IntrospectionException { BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { logger.info("{}",propertyDescriptor.getPropertyType()); logger.info("{}",propertyDescriptor.getReadMethod()); logger.info("{}",propertyDescriptor.getWriteMethod()); } } // 2.操纵bean的指定属性:age @Test public void testIntrospect2() throws Exception { User user = new User(); PropertyDescriptor pd = new PropertyDescriptor("age", User.class); // 得到属性的写方法,为属性赋值 Method method = pd.getWriteMethod(); method.invoke(user, 24); // 获取属性的值 method = pd.getReadMethod(); System.out.println(method.invoke(user, null)); } @Test public void testBeanUtil() throws Exception { User user = new User(); // 赋值 BeanUtils.setProperty(user,"name","tom"); BeanUtils.setProperty(user,"age",10); logger.info("user->{}",user); // 获取值 logger.info("the user's name is ->{}.",BeanUtils.getProperty(user,"name")); } 二、更强的反射工具

在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 SimpleBeanDefinitionRegistry 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); // 3、使用BeanWrapper包裹实例,使其更方便使用反射方法 BeanWrapperImpl beanWrapper = new BeanWrapperImpl(aClass); DefaultConversionService conversionService = new DefaultConversionService(); // 转换器在这里呦:使用lamdba表达式写一个转换器 conversionService.addConverter((Converter) source -> Integer.valueOf(Objects.requireNonNull(source.getValue()))); beanWrapper.setConversionService(conversionService); beanWrapper.setPropertyValues(beanDefinition.getPropertyValues()); Object bean = beanWrapper.getWrappedInstance(); System.out.println(bean); } } 3、ResolvableType

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

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

@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()); } 2、类型转化

我们从xml中搜集到的所有数据都是【字符串】,但是实际的类中的成员变量可能是数字,数组,集合,或者是复杂的引用数据类型,所以spring给我们提供了强大的转换服务(conversionService接口)。

public interface ConversionService { boolean canConvert(@Nullable Class sourceType, Class targetType); boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType); @Nullable T convert(@Nullable Object source, Class targetType); // 将给定的{@code source}转换为指定的{@code targetType}。 Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType); }

我们不妨看看DefaultConversionService的源码,更多核心的功能是在器父类中实现的,在构造实例时,他会默认传入大量可用转化器:

public class DefaultConversionService extends GenericConversionService { @Nullable private static volatile DefaultConversionService sharedInstance; public DefaultConversionService() { // 添加大量的默认的转换器 addDefaultConverters(this); } // 类似单例的获取方式 public static ConversionService getSharedInstance() { DefaultConversionService cs = sharedInstance; if (cs == null) { synchronized (DefaultConversionService.class) { cs = sharedInstance; if (cs == null) { cs = new DefaultConversionService(); sharedInstance = cs; } } } return cs; } // 添加适合大多数环境的转换器 public static void addDefaultConverters(ConverterRegistry converterRegistry) { addScalarConverters(converterRegistry); addCollectionConverters(converterRegistry); converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry)); converterRegistry.addConverter(new StringToTimeZoneConverter()); converterRegistry.addConverter(new ZoneIdToTimeZoneConverter()); converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter()); //...还有好多 } // 增加通用的转换器,例如集合、数组、对象等 public static void addCollectionConverters(ConverterRegistry converterRegistry) { ConversionService conversionService = (ConversionService) converterRegistry; converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService)); converterRegistry.addConverter(new CollectionToArrayConverter(conversionService)); converterRegistry.addConverter(new StringToCollectionConverter(conversionService)); converterRegistry.addConverter(new CollectionToObjectConverter(conversionService)); converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService)); //...还有好多 } // 新增标量的转化器,主要是字符串数字类型 private static void addScalarConverters(ConverterRegistry converterRegistry) { converterRegistry.addConverterFactory(new NumberToNumberConverterFactory()); converterRegistry.addConverterFactory(new StringToNumberConverterFactory()); converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter()); converterRegistry.addConverter(new StringToPropertiesConverter()); converterRegistry.addConverter(new PropertiesToStringConverter()); converterRegistry.addConverter(new StringToUUIDConverter()); //...还有好多 } }

我们可以编写如下的测试用例,可以将字符串转换为数字和列表:

@Test public void testConvertInteger(){ String source = "100"; ConversionService conversionService = new DefaultConversionService(); if(conversionService.canConvert(String.class,Integer.class)){ Integer target = conversionService.convert(source, Integer.class); logger.info("The number is {}.", target); } } @Test public void testConvertList(){ String source = "100,12,23,54,56"; ConversionService conversionService = new DefaultConversionService(); if(conversionService.canConvert(String.class, List.class)){ List target = conversionService.convert(source, List.class); logger.info("The number is {}.", target); } }

这种类型转换的能力非常有用,我们从【xml到java对象】,从【前端参数到java对象】,都需要这样的强大能力。

2、独立编写转化器

我们也可以实现自己的转化器,我们不妨写一个【从字符串到User类】的转化器,我们的转换器需要实现GenericConverter接口,这个可以仿照其他的转换器写:

我们可以先看看GenericConverter接口:

public interface GenericConverter { // 返回目标类型和源类型的一个set Set getConvertibleTypes(); // 新的方法 Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType); // 定义了一个 source-to-target class pair. final class ConvertiblePair { private final Class sourceType; private final Class targetType; ... 其他内容省略 } }

我们需要实现GenericConverter的两个方法:

public class UserConvert implements GenericConverter { @Override public Set getConvertibleTypes() { // 返回一个Set集合,其中的元素为一个只包含object(obj)的不可变集合 return Collections.singleton(new GenericConverter.ConvertiblePair(String.class, User.class)); } @Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { // 我们假设字符串的类型如下: name | age assert source != null; String[] nameAndAge = source.toString().split("\\|"); if(nameAndAge.length == 2){ return new User(nameAndAge[0].trim(),Integer.valueOf(nameAndAge[1].trim())); } else { throw new RuntimeException("转化出现异常."); } } }

在当前的测试用例中,我们将我们的convert添加到conversionService中:

@Test public void testConvertUser(){ String source = "Tom | 23"; // 这里必须使用子类的类型,接口并不提供addConverter方法 DefaultConversionService conversionService = new DefaultConversionService(); conversionService.addConverter(new UserConvert()); if(conversionService.canConvert(String.class, User.class)){ User target = conversionService.convert(source, User.class); logger.info("The user is {}.", target); } } // 结果 19:51:03.210 [main] INFO com.ydlclass.ToolsTest - The user is User{name='Tom', age=23}. 3.转换器源码:

spring在考虑转换的时候会考虑到 由 a -> b的转换,还会考虑到由a 到 b 的子类的转换。所以在spring中,转换器的结构是如下所示:

这一对对应的转换器们(因为能处理一对类型转换可能存在多个转换器),内部使用一个双端队列Deque来存储,保证顺序。

private static class ConvertersForPair { // 内部维护的队列 private final Deque converters = new ConcurrentLinkedDeque(); public void add(GenericConverter converter) { this.converters.addFirst(converter); } @Nullable public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { for (GenericConverter converter : this.converters) { // 此处表明,如果我们有特殊的需求,还可以实现ConditionalGenericConverter,实现特殊的匹配规则,连边中的converter可以有不同的匹配规则, // 当然通常情况下会返回第一个 if (!(converter instanceof ConditionalGenericConverter genericConverter) || genericConverter.matches(sourceType, targetType)) { return converter; } } return null; } } private static class Converters { // 存取通用的转换器,并不限定转换类型,一般用于兜底 private final Set globalConverters = new CopyOnWriteArraySet(); // 指定了类型对,对应的转换器们的映射关系。 // ConvertiblePair:表示一对,包含sourceType和targetType // ConvertersForPair:这一对对应的转换器们(因为能处理一对类型转换可能存在多个转换器),内部使用一个双端队列Deque来存储,保证顺序 private final Map converters = new ConcurrentHashMap(256); public void add(GenericConverter converter) { // 获得他的类型对儿 Set convertibleTypes = converter.getConvertibleTypes(); if (convertibleTypes == null) { // 如果没有限定转换类型,添加到globalConverters this.globalConverters.add(converter); } else { // 如果已经存在转换类型,我们写的都在这里 for (ConvertiblePair convertiblePair : convertibleTypes) { // 找到与之匹配的加进去,这里是个链表 getMatchableConverters(convertiblePair).add(converter); } } } @Nullable public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) { // 搜索完整的类型层次结构,父类---> // 比如想要搜索【虎猫 -> 老虎】,但如过虎猫有父类(猫) // 我们还需检索【猫 -> 老虎】 List> targetCandidates = getClassHierarchy(targetType.getType()); for (Class sourceCandidate : sourceCandidates) { for (Class targetCandidate : targetCandidates) { // 所有的类型都要匹配 ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate); // 找到一个就返回 GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair); if (converter != null) { return converter; } } } return null; } @Nullable private GenericConverter getRegisteredConverter(TypeDescriptor sourceType, TypeDescriptor targetType, ConvertiblePair convertiblePair) { // 根据convertiblePair获取ConvertersForPair ConvertersForPair convertersForPair = this.converters.get(convertiblePair); if (convertersForPair != null) { GenericConverter converter = convertersForPair.getConverter(sourceType, targetType); if (converter != null) { return converter; } } // 检查是否能匹配兜底的全局转换器 for (GenericConverter globalConverter : this.globalConverters) { if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) { return globalConverter; } } return null; } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3