史上最简单的Spring源码导读
做为Java开源世界的第⼀框架,Spring已经成为事实上的Java EE开发标准Spring框架最根本的使命是简化Java开发,因此学习、研究、掌握Spring框架成为每⼀位Java开发⼈员的必修课。⽽阅读源码则是学习Spring的最好⽅式之⼀。
Spring ⾥⾯最重要的特性就是 Ioc,可能你还会说 aop。其实 aop 的实现也是基于 ioc。Ioc (Inversion of Control),即“控制反转”,不是什么技术,⽽是⼀种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,⽽不是传统的在你的对象内部直接控制。
关于 Spring IOC 源码分析的⽂章⽹上很多,现在我就来另辟蹊径。Spring Ioc 的对象扭转以及 涉及到的核⼼接⼝来分析⼀下它的源码实现。
我把 Spring Ioc 的对象转换分为以下 4 个步骤:
Resource -> BeanDefinition -> BeanWrapper -> Object
1 Resource
Resouce 其实是⼀个接⼝,代表的是资源,在计算机⾥⾯从⼀个地⽅移动到另外⼀个地⽅所需要的东西
就是数据流,所以 Resource 实现了 InputStreamSource 接⼝,通过 InputStreamSource 接⼝可以获取到 Inputstream,这样就可以读取不同的 Bean 定义了。
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
Spring 可以定义不同类型的 bean,最后都可以封装成 Resource 通过 IO 流进⾏读取。 Spring 可以定义类型的 bean 对象:XML:这是 Spring 最开始定义 bean 的形式
Annotation :由于通过 XML 定义 bean 的繁琐,Spring 进⾏了改进可以通过 @Component 以及基于它的注解来定义 bean。例如:@Service,@Controller等等,它们都可以定义 bean ,只不过语义更加明确。
Class:通过 @Configuration 与 @Bean 注解定义,@Configuration 代理 xml 资源⽂件,⽽ @Bean 代替 <bean> 标签。
Properties/yml:通过 @EnableConfigurationProperties 与 @ConfigurationProperties 来定义 bean。这种形式在 Spring boot ⾃动注⼊⾥⾯⼤量使⽤。
2、BeanDefinition
望⽂⽣义,很显⽰这个是 Bean 对象的定义。 Spring 通过不同形式来定义 bean,最终会把这些定义转化成 BeanDefinition 保存在Spring 容器当中进⾏依赖注⼊。下⾯我们来看⼀下 BeanDefinition 的接⼝定义。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();
...
}
这个接⼝的定义很复杂但是,对于初始理解 spring ioc,只需要关⼼两个⽅法。
getConstructorArgumentValues:获取构造器注⼊定义的参数。
getPropertyValues:获取 setter 注⼊定义的参数。
所以 Spring ⽀持构造器注⼊与 setter 依赖注⼊。
1、构造器注⼊
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
2、setter注⼊
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
3、BeanWapper
其实什么是依赖注⼊,简单来说就是 Spring 帮我们创建对象。把创建对象写死在 Java ⽂件变成了通过不同的 Spring 配置可以注⼊不同的值。创建对象的职责由 Java ⽂件变成了 Spring 配置⽂件。
下⾯我就问⼀个简单的问题,如何创建对象。可能⼤家呵呵⼀笑,创建对象这还不简单。
1、⽆参构造器
Object obj = new Object();
obj.setXxx(xxx);
2、有参构造器
Object obj = new Object(xxx, yyyy);
obj.setXxx(xxx);
其实 Spring 也是这样来创建对象的,不信讲请看 : (⼊⼝⽅法 BeanFactory#getBean)
1. AbstractAutowireCapableBeanFactory#createBeanInstance() :通过反射 Constructor 调⽤配置的⽆参或者有参来创建对象实
例。通过 BeanDefinition#getConstructorArgumentValues 获取,并返回 BeanWrapper 对象。
2. AbstractAutowireCapableBeanFactory#populateBean():,获取到定义的 bean ⽣成的所有的定义的setter注⼊的属性
(BeanDefinition#getPropertyValues),然后遍历些这些属性,通过内省获取到对象所有的 属性描述器(
PropertyDescriptor),获取到,属性的 PropertyDescriptor#getWriteMethod ⽅法,也就是 setter ⽅法,依赖注⼊值。如果是普通属性或者⼀些复杂对象,⽐如普通属性 String, int, long 或者 classpath:*转换为 Resource 复杂对象等等,直接注⼊即可;对于引⽤类型对象,继续依赖注⼊直到所有的属性是普通属性为⽌。
3. AbstractAutowireCapableBeanFactory#initializeBean():调⽤ Spring ⾃定义的初始化⽅法⽐如:BeanPostProcessor 扩展以
及 init-method。
实例化对象返回 BeanWrapper,其实是为了依赖注⼊服务也就是上⾯的第⼆步。 这个接⼝的功能还是很复杂的,它继承了 4 个接⼝。
TypeConverter
PropertyEditorRegistry
PropertyAccessor
ConfigurablePropertyAccessor
下⾯就来分别介绍⼀下这些接⼝的功能。
3.1 TypeConverter
下⾯就是这个接⼝的定义。
public interface TypeConverter {
<T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;
<T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
throws TypeMismatchException;
<T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
throws TypeMismatchException;
}
它的作⽤就是⾃动类型转换,因为 Spring 作得太⽆感知了。你也许还没有感觉到它的存在。没关系,
我提⽰⼀下你应该就会明⽩。⽐如,声明⼀个⽤户对象这个对象既有 String 类型的名称,⼜有 Int 类型的年龄。 Spring 怎么知道属性的类型呢?这个就是 Spring 的⾃动类型转换。关于 我在之前就已经分析过了。
3.2 PropertyEditorRegistry
这个接⼝主要的作⽤是注册属性修改器(PropertyEditor),这个是 Java 内省⾥⾯的机制。
public interface PropertyEditorRegistry {
void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor);
PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath);
}
⼀般通过继承 java.beans.PropertyEditorSupport 来实现⾃定义的类型转换。在 Spring 内部有⼤量的实现,如下图所⽰:
3.3 PropertyAccessor
public interface PropertyAccessor {
boolean isReadableProperty(String propertyName);
boolean isWritableProperty(String propertyName);
cessor method failed
Class<?> getPropertyType(String propertyName) throws BeansException;
TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
Object getPropertyValue(String propertyName) throws BeansException;
void setPropertyValue(String propertyName, Object value) throws BeansException;
void setPropertyValue(PropertyValue pv) throws BeansException;
void setPropertyValues(Map<?, ?> map) throws BeansException;
void setPropertyValues(PropertyValues pvs) throws BeansException;
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
throws BeansException;
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException;
}
PropertyAccessor 这个接⼝是判断对象中的某个属性是否可读/可写,并且可以定⼊或者读取某个属性的值。从这个接⼝定义我们可以看出,它的使⽤其实就是真正⽤来依赖注⼊的。然后调⽤属性操作的写⼊操作,完全依赖注⼊。
3.4 ConfigurablePropertyAccessor
public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {
void setConversionService(ConversionService conversionService);
ConversionService getConversionService();
...
}
这个接⼝的功能和 PropertyEditorRegistry 接⼝⼀样,只不过后者是通过 java 内省来进⾏类型⾃动转换,⽽ConfigurablePropertyAccessor 接⼝是通过 Spring ⾃⼰定义的 onvert.ConversionService 来作类型转换类型转换。在 Spring 中默认使⽤的是 DefaultConversionService 来作⾃动类型转换⽀持,并且内部还添加了很多默认的类型转换。
public class DefaultConversionService extends GenericConversionService {
springboot aop/** Java 8's java.util.Optional class available? */
private static final boolean javaUtilOptionalClassAvailable =
ClassUtils.isPresent("java.util.Optional", ClassLoader());
/** Java 8's java.time package available? */
private static final boolean jsr310Available =
ClassUtils.isPresent("java.time.ZoneId", ClassLoader());
/** Java 8's java.util.stream.Stream class available? */
private static final boolean streamAvailable = ClassUtils.isPresent(
"java.util.stream.Stream", ClassLoader());
public DefaultConversionService() {
addDefaultConverters(this);
}
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
addScalarConverters(converterRegistry);
addCollectionConverters(converterRegistry);
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
if (jsr310Available) {
}
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
if (javaUtilOptionalClassAvailable) {
converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}
}
public static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。