我就从用最简单的说法来说,不一定准确,spring为我们做了2件事:
- 省去了我们创建对象的操作
- 给我们声明的属性赋值
我们从最简单的bean的生成开始写起,我模仿的框架暂时未考虑支持xml配置的形式,全部采用注解的方式,实现主要功能。
好了我们开始进入正题,首先从bean的生产开始说起
首先先说spring是如何做的,相信用过spring的都知道下面这个标签,包扫描配置:
<context:component-scan base-package="com.bauer.java.activiti"/>
通过解析xml文件,首先找到(可能有的同学不知道这是如何找到的,可以留言,或者自行百度spring.handlers)
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
我们发现实际的component-scan的解析类是 ComponentScanBeanDefinitionParser 实际的扫描生成beandefination。
大致步骤:
- 分割路径
- 扫描代用@component注解的类(包括注解上包含的@componet,如@Controller类似的注解)
- 生成beandefination
值得注意的是spring的扫描采用的是asm技术扫描的,而非是加载类,然后通过Type信息去判断注解的,还有一个问题就是,只要包名一致spring也会去扫描jar包中的class。
华丽的风格线-----------------
模仿框架称之为autunm
bean加载
autunm暂时没有实现xml配置文件的方式,所以项目的起点设置在了web.xml中如下图配置所示
<context-param>
<param-name>SCAN_PATH</param-name>
<param-value>com.bauer.java.activiti</param-value>
</context-param>
<listener>
<listener-class>com.bauer.framework.autumn.WebStartPoint</listener-class>
</listener>
SCAN_PATH是包的扫描路径,接下来通过servletContext获取到路径,暂时还未支持多路径,首先获取到项目路径,然后通过项目路径获取到所有class的包路径,走后去扫描带@Bean注解的class
if (beanFactory == null) {
beanFactory = new AutowiredBeanFactory();
}
String pkgPath = servletContext.getInitParameter(SCAN_PATH_NAME);
//扫描注解类生成
String classPath = this.getClass().getResource("/").getPath();
//获取所有class的路径
List<String> listpath = PathUtils.getPkgPath(classPath, pkgPath);
beanFactory.loadBeanDefination(Thread.currentThread().getContextClassLoader(), listpath);
注意,我采用的是通过类型信息判断类是否有@Bean注解具体的实现如下,
Class loadClass = classLoader.loadClass(pkg);
annotationPaser = new AnnotationPaser(loadClass);
if (annotationPaser.hasAnnotion(Bean.class.getName())) {
BeanDefination beanDefination = new BeanDefination();
beanDefination.setName(loadClass.getName());
beanDefination.setBeanClass(loadClass);
beanNames.add(loadClass.getName());
beanDefinationMap.put(beanDefination.getName(), beanDefination);
}