以下文中spring特指spring frameWork项目,不含其它:如spring cloud等。

  作为刚开始研究spring源码的小白,对于spring两大核心功能之一的IOC,虽说大致了解了Bean的注册与实例化过程、PostProcessors对于bean的实例化的干预等,还是觉得自己要手动实践下IOC功能,算是考验下自己是否对spring源码有了初步的入门。此次模拟基于annotation风格,也比较符合现在spring的开发主流趋势。由于是手动实现,当然不能通过springboot构建项目,采用idea或eclipse创建一个普通的web工程吧。按照开发的先后顺序吧。

  自定义的几个注解

  熟悉基于配置的风格的童鞋都知道,spring里面最最常用的注解@ComponentScan,@Component和@Autowired。稍稍说下这三个注解的作用,@ComponentScan:对于指定的目录下的Bean的扫描。@Component:描述一个普通的pojo,告知spring上下文这个pojo需要被spring容器所管理,也就是spring 中的bean。@Autowired:Bean中属性的自动注入,默认注入是按照bytype。那么,照葫芦画瓢,对应的定义了下面三个注解

 @Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
String value() default "";
} @Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
String value();
} @Retention(RetentionPolicy.RUNTIME)
public @interface MyComponentScan {
String value();
}

  注意,每个自定义注解至少应该添加注解@Retention,并且指定value是runtime。@Retention是用来修饰注解的注解,也就是元注解。RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。

  定义几个pojo

  一个是配置类MyConfigure,用于指定扫描路径,功能单一。加上自定义的注解@MyComponentScan。指定扫描com.entity路径下的类。

 package com.entity;
import com.annotate.MyComponentScan; @MyComponentScan("com.entity")
public class MyConfigure { }

  两个简单的实体类Order和User,加上自定义注解@MyComponent。其中Order中有个成员属性User,加入注解@MyAutowired。

 package com.entity;

 import com.annotate.MyAutowired;
import com.annotate.MyComponent; @MyComponent("myComponent")
public class Order {
@MyAutowired
private User user; public void print(){
System.out.println("This is order");
} public void printUser(){
this.user.printMessage();
}
}
 package com.entity;

 import com.annotate.MyComponent;

 @MyComponent("myComponent")
public class User {
public void print(){
System.out.println("This is user");
} public void printMessage(){
System.out.println("This is user from order");
}
}

  spring上下文的模拟

  MySpringApplicationContext实现的spring上下文,主要包含了根据路径扫描的注册Bean方法和getBean过程,也包含一个主要的成员属性map,用于存放上下文中被注册并实例化的Bean。

 package com.myspring;

 import com.annotate.MyAutowired;
import com.annotate.MyComponent;
import com.annotate.MyComponentScan; import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; public class MySpringApplicationContext {
/**
* 存放bean的map(模仿spring beanfactory 中的map)
*/
private HashMap<String,Object> beanFactoryMap; public MySpringApplicationContext(Class clazz){
beanFactoryMap = new HashMap<String, Object>();
this.packageScan(clazz);
} public void packageScan(Class configureClazz){
//获取扫描路径
MyComponentScan myComponentScan = (MyComponentScan) configureClazz.getAnnotation(MyComponentScan.class);
if(myComponentScan == null){
return;
}
/**
* 获取待扫描的目录
*/
String packageName = myComponentScan.value();
String rootPath = this.getClass().getResource("/").getPath();
String packagePath = packageName.replaceAll("\\.","/");
/**
* 获取扫描目录的绝对地址
*/
String classFilePath = rootPath + packagePath;
File file = new File(classFilePath);
String[] files = file.list();
if(files != null && files.length>0){
for(String subFile:files){
try {
String beanName = subFile.split("\\.")[0];
Class clazz = Class.forName(packageName +"."+ beanName);
if(clazz.isAnnotationPresent(MyComponent.class)){
Object object = clazz.newInstance();
beanFactoryMap.put(beanName.toLowerCase(),object);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//处理注入的问题(模拟@Autowired)
if(!beanFactoryMap.isEmpty()){
Iterator iterator = beanFactoryMap.entrySet().iterator();
while (iterator.hasNext()){
try {
Map.Entry entry = (Map.Entry) iterator.next();
Class clazz = entry.getValue().getClass();
Field[] fields = clazz.getDeclaredFields();
if(fields != null && fields.length > 0){
for(Field field:fields){
field.setAccessible(true);
MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
if(myAutowired != null){
field.set(entry.getValue(),beanFactoryMap.get(field.getName()));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
} } public Object getBean(String beanName){
return this.beanFactoryMap.get(beanName);
} }

  测试

  主要测试内容是Bean的成功注册并实例化,Bean的成功注入。

 package com.test;

 import com.entity.User;
import com.myspring.MySpringApplicationContext;
import com.entity.MyConfigure;
import com.entity.Order;
public class Test {
public static void main(String[] args) {
MySpringApplicationContext mySpringApplicationContext = new MySpringApplicationContext(MyConfigure.class);
User user = (User) mySpringApplicationContext.getBean("user");
user.print();
Order order = (Order) mySpringApplicationContext.getBean("order");
order.print();
/**
* 用于验证Order中是否成功注入User对象
*/
order.printUser();
}
}

  结果输出

 This is user
This is order
This is user from order

  以上是手动实现spring IOC功能的全过程,当然这只是spring机制的皮毛的皮毛,希望给有欲望去了解,但还未实施了解spring源码的童鞋以帮助,抛砖引玉。实力有限,欢迎各位专家同仁批评指正。

最新文章

  1. TreeView checkbox 全选
  2. linux之间文件传输问题
  3. media type 与 media query
  4. openstack 采用conductor的原因
  5. c++11 新特性之 autokeyword
  6. Jquery基础教程第二版学习记录
  7. opencv3.1自带demo的介绍和运行操作。转载
  8. appium python andiroid自动化文档整理笔记。
  9. oracle按某个字段分组然后从每组取出最大的一条纪录
  10. springMVC中文乱码问题解决
  11. Spring定时任务quartz表达式
  12. emacs 配置
  13. linux下安装jdk 详细步骤(一条命令即可安装)
  14. 2.05-random-uesr-proxy
  15. python中集合-set
  16. flume遇到的问题
  17. 第三百二十九节,web爬虫讲解2—urllib库爬虫—ip代理—用户代理和ip代理结合应用
  18. 洛谷P2463 Sandy的卡片【后缀数组】【二分】
  19. Linux sendmail
  20. 配置thunderbirdmail

热门文章

  1. Asp.Net Core中配置使用Kindeditor富文本编辑器实现图片上传和截图上传及文件管理和上传(开源代码.net core3.0)
  2. linux安装redis及外网访问
  3. Python项目生成所有依赖包的清单
  4. NOIP模拟测试36考试反思
  5. go xml 序列化
  6. 深入理解@LoadBalanced注解的实现原理与客户端负载均衡
  7. 使用vue-cli搭建项目开发环境
  8. AI的真实感
  9. 推荐Java五大微服务器及其代码示例教程
  10. Servlet中response的相关案例(重定型,验证码,ServletContext文件下载)