因为种种原因 本人不得不放弃之前开发的四部分 四部分就当一个小框架来实现了最简单的扫包 注册bean并且操作 就只在于让我初步了解了spring的最基本的工作原理 在本人的思考下 准备进军更复杂完善的手写spring项目的行动 愿成功
本篇将会实现最基本的IOC容器结构与实现(从一个轮子新手的视角 一步一步完成)
项目结构树(github上的minispring项目)
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─minispring
│ │ │ ├─aop
│ │ │ │ │ Advice.java
│ │ │ │ │ Advisor.java
│ │ │ │ │ AfterAdvice.java
│ │ │ │ │ AfterReturningAdvice.java
│ │ │ │ │ BeforeAdvice.java
│ │ │ │ │ ClassFilter.java
│ │ │ │ │ MethodBeforeAdvice.java
│ │ │ │ │ MethodMatcher.java
│ │ │ │ │ Pointcut.java
│ │ │ │ │ PointcutAdvisor.java
│ │ │ │ │ TargetSource.java
│ │ │ │ │ TruePointcut.java
│ │ │ │ │
│ │ │ │ ├─aspectj
│ │ │ │ │ AspectJExpressionPointcut.java
│ │ │ │ │
│ │ │ │ ├─framework
│ │ │ │ │ AdvisedSupport.java
│ │ │ │ │ AopProxy.java
│ │ │ │ │ CglibAopProxy.java
│ │ │ │ │ JdkDynamicAopProxy.java
│ │ │ │ │ MethodInvocation.java
│ │ │ │ │ ProxyFactory.java
│ │ │ │ │ ReflectiveMethodInvocation.java
│ │ │ │ │ SingletonTargetSource.java
│ │ │ │ │ TargetSource.java
│ │ │ │ │
│ │ │ │ └─support
│ │ │ │ DefaultPointcutAdvisor.java
│ │ │ │
│ │ │ ├─beans
│ │ │ │ │ BeansException.java
│ │ │ │ │ BeanWrapper.java
│ │ │ │ │ PropertyValue.java
│ │ │ │ │ PropertyValues.java
│ │ │ │ │ SimpleTypeConverter.java
│ │ │ │ │ TypeConverter.java
│ │ │ │ │ TypeMismatchException.java
│ │ │ │ │
│ │ │ │ └─factory
│ │ │ │ │ AutowireCapableBeanFactory.java
│ │ │ │ │ BeanFactory.java
│ │ │ │ │ BeanFactoryAware.java
│ │ │ │ │ BeanNameAware.java
│ │ │ │ │ ConfigurableBeanFactory.java
│ │ │ │ │ ConfigurableListableBeanFactory.java
│ │ │ │ │ DisposableBean.java
│ │ │ │ │ HierarchicalBeanFactory.java
│ │ │ │ │ InitializingBean.java
│ │ │ │ │ ListableBeanFactory.java
│ │ │ │ │ ObjectFactory.java
│ │ │ │ │
│ │ │ │ ├─config
│ │ │ │ │ BeanDefinition.java
│ │ │ │ │ BeanFactoryPostProcessor.java
│ │ │ │ │ BeanPostProcessor.java
│ │ │ │ │ BeanReference.java
│ │ │ │ │ ConfigurableBeanFactory.java
│ │ │ │ │ DependencyDescriptor.java
│ │ │ │ │ PlaceholderResolver.java
│ │ │ │ │ PropertyPlaceholderResolver.java
│ │ │ │ │ PrototypeScope.java
│ │ │ │ │ Scope.java
│ │ │ │ │ ScopedBeanFactoryPostProcessor.java
│ │ │ │ │ ScopedProxyBeanPostProcessor.java
│ │ │ │ │ ScopedProxyFactory.java
│ │ │ │ │ ScopeRegistrar.java
│ │ │ │ │ SingletonBeanRegistry.java
│ │ │ │ │ SingletonScope.java
│ │ │ │ │
│ │ │ │ ├─support
│ │ │ │ │ AbstractAutowireCapableBeanFactory.java
│ │ │ │ │ AbstractBeanDefinitionReader.java
│ │ │ │ │ AbstractBeanFactory.java
│ │ │ │ │ BeanDefinitionReader.java
│ │ │ │ │ BeanDefinitionRegistry.java
│ │ │ │ │ CglibSubclassingInstantiationStrategy.java
│ │ │ │ │ ConstructorResolver.java
│ │ │ │ │ DefaultListableBeanFactory.java
│ │ │ │ │ DefaultSingletonBeanRegistry.java
│ │ │ │ │ DisposableBeanAdapter.java
│ │ │ │ │ InstantiationStrategy.java
│ │ │ │ │ SimpleInstantiationStrategy.java
│ │ │ │ │
│ │ │ │ └─xml
│ │ │ │ AbstractNamespaceHandler.java
│ │ │ │ BeanDefinitionDocumentReader.java
│ │ │ │ ContextNamespaceHandler.java
│ │ │ │ DefaultBeanDefinitionDocumentReader.java
│ │ │ │ DefaultDocumentLoader.java
│ │ │ │ DefaultNamespaceHandlerResolver.java
│ │ │ │ DocumentLoader.java
│ │ │ │ NamespaceHandler.java
│ │ │ │ NamespaceHandlerResolver.java
│ │ │ │ XmlBeanDefinitionReader.java
│ │ │ │ XmlBeanDefinitionStoreException.java
│ │ │ │
│ │ │ ├─context
│ │ │ │ │ ApplicationContext.java
│ │ │ │ │ ApplicationContextAware.java
│ │ │ │ │ ApplicationEvent.java
│ │ │ │ │ ApplicationListener.java
│ │ │ │ │ ConfigurableApplicationContext.java
│ │ │ │ │
│ │ │ │ ├─event
│ │ │ │ │ ApplicationEventMulticaster.java
│ │ │ │ │ ContextClosedEvent.java
│ │ │ │ │ ContextRefreshedEvent.java
│ │ │ │ │ SimpleApplicationEventMulticaster.java
│ │ │ │ │
│ │ │ │ └─support
│ │ │ │ AbstractApplicationContext.java
│ │ │ │ AbstractRefreshableApplicationContext.java
│ │ │ │ AbstractXmlApplicationContext.java
│ │ │ │ ApplicationContextAwareProcessor.java
│ │ │ │ ClassPathXmlApplicationContext.java
│ │ │ │ FileSystemXmlApplicationContext.java
│ │ │ │
│ │ │ ├─core
│ │ │ │ │ DefaultParameterNameDiscoverer.java
│ │ │ │ │ ParameterNameDiscoverer.java
│ │ │ │ │
│ │ │ │ ├─convert
│ │ │ │ │ │ ConversionException.java
│ │ │ │ │ │ ConversionService.java
│ │ │ │ │ │
│ │ │ │ │ ├─converter
│ │ │ │ │ │ ConditionalConverter.java
│ │ │ │ │ │ ConditionalGenericConverter.java
│ │ │ │ │ │ Converter.java
│ │ │ │ │ │ ConverterFactory.java
│ │ │ │ │ │ ConverterRegistry.java
│ │ │ │ │ │ GenericConverter.java
│ │ │ │ │ │
│ │ │ │ │ └─support
│ │ │ │ │ DefaultConversionService.java
│ │ │ │ │ GenericConversionService.java
│ │ │ │ │ StringToBooleanConverter.java
│ │ │ │ │ StringToByteConverter.java
│ │ │ │ │ StringToCharacterConverter.java
│ │ │ │ │ StringToDateConverter.java
│ │ │ │ │ StringToDoubleConverter.java
│ │ │ │ │ StringToFloatConverter.java
│ │ │ │ │ StringToIntegerConverter.java
│ │ │ │ │ StringToLongConverter.java
│ │ │ │ │ StringToShortConverter.java
│ │ │ │ │
│ │ │ │ ├─env
│ │ │ │ │ AbstractEnvironment.java
│ │ │ │ │ ConfigurableEnvironment.java
│ │ │ │ │ Environment.java
│ │ │ │ │ EnvironmentPropertySource.java
│ │ │ │ │ MapPropertySource.java
│ │ │ │ │ MutablePropertySources.java
│ │ │ │ │ Profile.java
│ │ │ │ │ PropertySource.java
│ │ │ │ │ PropertySources.java
│ │ │ │ │ StandardEnvironment.java
│ │ │ │ │ SystemEnvironmentPropertySource.java
│ │ │ │ │ SystemPropertySource.java
│ │ │ │ │
│ │ │ │ └─io
│ │ │ │ ClassPathResource.java
│ │ │ │ DefaultResourceLoader.java
│ │ │ │ FileSystemResource.java
│ │ │ │ Resource.java
│ │ │ │ ResourceLoader.java
│ │ │ │ UrlResource.java
│ │ │ │
│ │ │ ├─util
│ │ │ │ ClassUtils.java
│ │ │ │
│ │ │ └─web
│ │ │ └─context
│ │ │ └─request
│ │ │ RequestScope.java
│ │ │ SessionScope.java
│ │ │
│ │ └─resources
│ │ └─META-INF
│ │ spring.handlers
在实现ioc之前 需要先完全理解Bean对象是什么 根据代码随想录上面说的 Bean是由Spring ioc容器实例化并且管理的对象 在此之前 我也初步了解了bean在bean容器里的操作 bean在容器里面需要一个元数据来识别 在这个新项目当中 用了将bean的元数据转换成spring能够识别的BeanDefinetion对象 bean以及它们之间的关系都反应在配置元数据当中去
所以 我们需要先定义一个BeanDefinition对象 来定义Bean的信息
但是在定义这个对象之前 需要我们定义一些基本需要的属性 包括我们要管理的属性 bean的作用域 bean的异常处理定义
/**
* Bean异常
* @author shanshan
* @date 2014-4-2 定义bean异常
*/
public class BeanException extends RuntimeException{
public BeanException(String message){
super(message);
}
public BeanException(String message,Throwable cause){
super(message,cause);
}
}
//定义非检查型异常 两种方式一种带消息 一种带消息+底层异常如:NullptrException
//消息和原因两种构造方式
这里定义了异常的两种方式
/**
* 属性值模型
* @author shanshan
* @date 2014-4-2 定义bean异常
*/
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
定义属性 属性很简单 一个字段名和一个属性 spring容器会对其进行管理 如此定义比之前更方便了自定义以及管理
/**
* 属性值集合
* 放置管理属性
* Created by shanshan on 2018/3/19.
*/
public class PropertyValues {
private final List<PropertyValue> propertyValueList=new ArrayList<>();
/**
* 添加属性值 放入一个属性对象*/
public void addPropertyValue(PropertyValue propertyValue){
this.propertyValueList.add(propertyValue);
}
/**
* 获取属性值集合转成的数组*/
public PropertyValue[] getPropertyValues(){
return this.propertyValueList.toArray(new PropertyValue[0]);
}
/**
* 根据属性名获取属性值*/
public PropertyValue getPropertyValue(String propertyName){
for (PropertyValue propertyValue:propertyValueList){
if (propertyValue.getName().equals(propertyName)){
return propertyValue;
}
}
return null;
}
}
当然一个bean不可能只有一个属性 还需要定义一个属性值集合
有了上面的基本定义好的东西 接下来需要定义bean的抽象了 根据spring的设计思想 我们的spring需要知道以下几个元素
bean的名字
bean的类型
bean的多个属性
bean的作用域
初始化方法以及销毁方法
/**
* bean的定义
* @author dongms
* @date 2020/07/09
*/
public class BeanDefinition {
private Class<?> beanClass; //bean的类型
private String beanClassName;
private PropertyValues propertyValues; //bean的属性
private String initMethodName; //初始化方法
private String destroyMethodName; //销毁方法
private boolean singleton = true; //是否单例
private boolean prototype = false; //是否多例
/**
* 默认作用域
*/
public static final String SCOPE_SINGLETON = "singleton";
public static final String SCOPE_PROTOTYPE = "prototype";
}
由此 我们定义出了bean的抽象元数据 根据这些属性 spring就可以掌握并且管理bean了
public class test {
@Test
public void testBasicDefine(){
PropertyValue pv = new PropertyValue("name","杜小猪");
PropertyValue pv2 = new PropertyValue("active",false);
PropertyValues pvs = new PropertyValues();
pvs.addPropertyValue(pv);
pvs.addPropertyValue(pv2);
System.out.println(pvs);
BeanDefinition bd = new BeanDefinition("com.dms.shanshan.beans.Person",pvs);
System.out.println(bd.toString());
}
}
进行测试查看输出
正常输出 并且能获取到信息 即说明已成功
综上我们实现了简单的bean定义模式
后记
仓库地址(不断更新):
全系列:杜明珅的手搓spring迷你框架系列
上一篇:手搓spring迷你框架之旅-04 Controller请求参数的实现
下一篇: