自己实现spring(一) ?? ioc容器实现

发布时间:2021-11-30 17:45:49


前言:加深对spring的理解,把spring ioc的大致流程抽出来,自己动手撸一个简洁版的



新建一个maven工程,这里使用idea工具

pom文件只依赖一个servlet


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.fanday
spring
1.0-SNAPSHOT


javax.servlet
javax.servlet-api
3.0.1
provided



项目结构:


ioc spring的bean工厂,完成定位 注册 初始化 注入等过程mvc spring的web层mvc框架,负责请求的分发demo 用于测试框架使用

编写接口定义


ApplicationContext主要定义获取bean的方法,有根据id获取的,也有获取所有bean的

package com.fanday.ioc;
import java.util.Map;

public interface ApplicationContext {
/**
* 根据id获取bean
* @param id
* @return
*/
Object getBean(String id);

/**
* 根据id获取特定类型的bean,完成强转
* @param id
* @param clazz
* @param
* @return
*/
T getBean(String id,Class clazz);

/**
* 获取工厂内的所有bean集合
* @return
*/
Map getBeans();
}

BeanRegister定义向工厂注册bean 和BeanDefinition的方法

package com.fanday.ioc;
import com.fanday.ioc.support.BeanDefinition;

import java.util.List;

public interface BeanRegister {
/**
* 向工厂内注册BeanDefinition
* @param bds
*/
void registBeanDefinition(List bds);

/**
* 向工厂内注册bean实例对象
* @param id
* @param instance
*/
void registInstanceMapping(String id,Object instance);
}



support包主要是一些默认的工厂实现,annotation包是一些需要的注解



package com.fanday.ioc.annotation;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Target(ElementType.TYPE)//作用在类上面
@Documented
public @interface Controller {
String value() default "";
}

package com.fanday.ioc.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Component {
String value() default "";
}

package com.fanday.ioc.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用在字段上面
@Documented
public @interface Autowire {
String value() default "";
}

package com.fanday.ioc.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})//作用在类和方法 仿照springmvc的套路来
@Documented
public @interface RequestMapping {
String value() default "";
}

package com.fanday.ioc.annotation;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)//作用在方法的参数上面
@Documented
public @interface RequestParam {
String value() default "";
}


resources下新建一个applicationContext.properties文件用于配置,容器启动时要扫描的包
scanPackage=com.fanday.demo



AnnotationApplicationContext 容器的具体实现


package com.fanday.ioc.support;

import com.fanday.ioc.ApplicationContext;
import com.fanday.ioc.BeanRegister;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationApplicationContext implements ApplicationContext,BeanRegister {
private Map instanceMapping = new ConcurrentHashMap();

//保存所有bean的信息,主要包含bean的类型 id等信息
private List beanDefinitions = new ArrayList();
//配置文件的config,这里为了简单我们使用properties文件
private Properties config = new Properties();

public AnnotationApplicationContext(String location){
InputStream is = null;
try{

//1、定位
is = this.getClass().getClassLoader().getResourceAsStream(location);

//2、载入
config.load(is);

//3、注册
register();

//4、实例化
createBean();

//5、注入
populate();

}catch(Exception e){
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 调用具体委派的注入类进行注入
*/
private void populate() {
Populator populator = new Populator();
populator.populate(instanceMapping);
}

/**
* 调用具体的创建对象创建bean
*/
private void createBean() {
BeanCreater creater = new BeanCreater(this);
creater.create(beanDefinitions);
}

/**
* 调用具体的注册对象注册bean信息
*/
private void register() {
BeanDefinitionParser parser = new BeanDefinitionParser(this);
parser.parse(config);
}

public Object getBean(String id) {
return instanceMapping.get(id);
}
public Properties getConfig() {
return this.config;
}

public T getBean(String id, Class clazz) {
return (T)instanceMapping.get(id);
}

public Map getBeans() {
return instanceMapping;
}

public void registBeanDefinition(List bds) {
beanDefinitions.addAll(bds);
}

public void registInstanceMapping(String id, Object instance) {
instanceMapping.put(id,instance);
}

}

BeanDefinitionParser完成扫描包下bean信息的解析注册


package com.fanday.ioc.support;

import com.fanday.ioc.BeanRegister;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Properties;

public class BeanDefinitionParser {
//配置的扫描包的key
public static final String SCAN_PACKAGE = "scanPackage";
//容器注册对象
private BeanRegister register;
public BeanDefinitionParser(BeanRegister register){
this.register = register;
}

public void parse(Properties properties){
//获取要扫描的包
String packageName = properties.getProperty(SCAN_PACKAGE);
//执行注册
doRegister(packageName);
}


private void doRegister(String packageName) {
//获取此包名下的绝对路径
URL url = getClass().getClassLoader().getResource("./"+packageName.replaceAll("\.","/"));
File dir = new File(url.getFile());
//循环遍历 递归找到所有的java文件
for (File file:dir.listFiles()){
if(file.isDirectory()){
//文件夹-->递归继续执行
doRegister(packageName+"."+file.getName());
}else {
//处理文件名来获取类名 运行时获取到的是class文件
String className = packageName+"."+file.getName().replaceAll(".class","").trim();
//调用BeanDefinitionGenerator.generate(className)方法,来处理
//1.类带有容器要处理的注解,则解析id生成BeanDefinition集合返回
//2.不带有需要处理的注解 直接返回null
List definitions = BeanDefinitionGenerator.generate(className);
if(definitions == null)continue;
//调用容器的注册方法来完成bean信息的注册
this.register.registBeanDefinition(definitions);
}
}

}
}

BeanDefinitionGenerator根据具体的类名来完成BeanDefinition的生成


package com.fanday.ioc.support;

import com.fanday.ioc.annotation.Component;
import com.fanday.ioc.annotation.Controller;

import java.util.ArrayList;
import java.util.List;

public class BeanDefinitionGenerator {

public static List generate(String className){
try {
Class clazz = Class.forName(className);
String[] ids = generateIds(clazz);
if(ids==null)return null;
List list = new ArrayList();
for (String id:ids){
list.add(new BeanDefinition(id,clazz));
}
return list;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}


/**
* 生成id数组
* 1.带有@Controller 注解但是注解value没给值,@Controller一般没有
* 接口定义,用类的全名作为id返回ids长度为1
* 2.@Component 没有value 获取所有的实现的接口,接口名为id,返货ids数组
* 长度是实现的接口个数
* 3.@Component 有value 返回id=value
* 4.不带容器要实例化的注解 null
*/
private static String[] generateIds(Class clazz) {
String[] ids = null;
if (clazz.isAnnotationPresent(Controller.class)) {
ids = new String[]{clazz.getName()};
} else if (clazz.isAnnotationPresent(Component.class)) {
Component component = (Component) clazz.getAnnotation(Component.class);
String value = component.value();
if (!"".equals(value)) {
ids = new String[]{value};
} else {
Class[] interfaces = clazz.getInterfaces();
ids = new String[interfaces.length];
//如果这个类实现了接口,就用接口的类型作为id
for (int i = 0; i < interfaces.length; i++){
ids[i] = interfaces[i].getName();
}
return ids;
}
}
return ids;
}

}

package com.fanday.ioc.support;

public class BeanDefinition{
private String id;
private Class clazz;
public BeanDefinition(String id, Class clazz){
this.id = id;
this.clazz = clazz;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Class getClazz() {
return clazz;
}

public void setClazz(Class clazz) {
this.clazz = clazz;
}

public Object getInstance(){
try {
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

BeanCreater比较简单,创建bean并且添加到容器工厂


package com.fanday.ioc.support;

import com.fanday.ioc.BeanRegister;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Properties;

public class BeanCreater {

private BeanRegister register;
public BeanCreater(BeanRegister register){
this.register = register;
}

public void create(List bds){
for (BeanDefinition bd:bds){
doCreate(bd);
}
}

private void doCreate(BeanDefinition bd) {
Object instance = bd.getInstance();
this.register.registInstanceMapping(bd.getId(),instance);
}
}


bean都初始化完成了,接下来进行bean之间的依赖注入



package com.fanday.ioc.support;

import java.lang.reflect.Field;
import java.util.Map;
import com.fanday.ioc.annotation.Autowire;

public class Populator {

public Populator(){
}

public void populate(Map instanceMapping){
//首先要判断ioc容器中有没有东西
if(instanceMapping.isEmpty())return;

//循环遍历每一个容器中得对象
for (Map.Entry entry:instanceMapping.entrySet()){
//获取对象的字段
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field:fields){
if(!field.isAnnotationPresent(Autowire.class))continue;
Autowire autowire = field.getAnnotation(Autowire.class);
//后去字段要注入的id value 为空则按类名 接口名自动注入
String id = autowire.value();
if("".equals(id))id = field.getType().getName();
field.setAccessible(true);
try {
//反射注入
field.set(entry.getValue(),instanceMapping.get(id));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}


至此 ioc的整个流程大致完成,我们来编写测试







ok,ioc容器实现已基本完成,下次一起来撸mvc


相关文档

  • 梦见文具盒 铅笔盒
  • InnoDB Hot Backup 程序(ibbackup)备份innodb 表
  • 我飞故我在
  • 苹果手表如何降级
  • (DP)673. 最长递增子序列的个数
  • 公司逃税怎么举报
  • 成语万金不换
  • 黑色衬衫怎么搭配
  • 小学义务教育均衡发展督导评估自查自评报告
  • 一对浪漫情侣签名
  • 中学各学科独特的复习方法
  • android 从视频中提取音频及录音后合并到视频
  • 腿粗的女生适合穿长筒袜吗 腿粗穿小腿袜好还是过膝袜好
  • 渴望宁静
  • 抽象类(Abstract Class)与接口(Interface)区别
  • 通信广场营业员工作自我总结
  • LeetCode之通过二叉树的中序遍历和前序遍历来还原二叉树
  • 小兵张嘎电影观后感400字5篇
  • 公务员报考个人简历怎么写
  • 生产车间主任工作计划素材模板
  • 在Andorid开发项目中遇到的Bug记录(续)
  • 2017公共卫生执业医师考试考前提高练习题
  • 苏州园林的拙政园简介
  • 读书的名言和作者
  • 圆耳朵的表哥
  • 《时间简史》读书笔记_时间简史读后感3000字 - 读书笔记
  • 天正建筑中如何调整标注尺寸的比例
  • 全国公益性饲料粮交易会成交达153亿元
  • java常用的加密解密方法
  • 项目年度安全工作总结及2019年工作计划
  • 猜你喜欢

  • ipad屏幕漏液会扩大吗
  • 【最新2018】201X元宵节祝福语贺词集锦-范文word版 (8页)
  • 液相色谱分析方法建立-系列1 之基本理论及色谱评价
  • 最新视觉设计在环海商机网络中的解读
  • 初一话题作文-开心的五一劳动节500字.doc
  • 新疆2016年上半年放射医学技术高级(师)专业实践能力考试题
  • 英语专业综合英语课教学改革初探
  • “顾客至上,服务至上”??
  • 扬中市兴隆中心小学社团活动记录
  • 2019年最新电话客服精品个人年终工作总结精品合集报告
  • 【推荐】2019秋九年级物理全册第十五章电流和电路第5节串、并联电路中电流的规律课件新版新人教版.ppt
  • Jmeter接口测试文件上传(一):对上传文件实现B64编码
  • 大学生法院法庭实*报告
  • 大连市2011年初中毕业升学考试数学试题
  • 2018年初二英语上学期预*知识点总结
  • 2009年瑟肽暾?檀?ぷ髯芙屺精)
  • 铁道部关于明确时速120公里及以下铁路隧道设计有关要求的通知 铁建设〔2012〕159号
  • 部队文化墙的高清图片展示
  • 关于打一地名的脑筋急转弯
  • 长春版四年级语文上册 25.望庐山瀑布(教案)【新版】
  • 论关联企业中少数股东的利益保护
  • 2016-2020年中国KTV场所LED照明市场深度全景调研及“十三五”发展前景预测报告目录
  • 浅析生态伦理问题及其思想政治教育解决途径——以野生动物非法贸
  • python建立逻辑回归模型
  • 青春校园励志散文篇精选
  • 宝宝手指脱皮什么药膏
  • 小学一年级下册数学教案一年级下册数学教案-第一单元 第3课时 解决问题
  • 汽车结构 第16章_液力机械传动和机械式无极变速器-PPT精选文档
  • 2008中国大学教育学本科A
  • 人教版高中化学选修四高二化学期末复*盐类的水解巩固练*
  • 一封来自前ThoughtWorks总监咨询师 致国内程序员的一封信
  • 习惯决定学习成绩读后感精选多篇
  • 高一地理 4.3 经济发达地区的可持续发展教案 鲁教版
  • 胃蛋白酶原PG简介 PPT
  • 金蝶云K3 Cloud V6.1_产品培训_基础领域_集成*台
  • 2018二房东房屋租赁合同范本
  • 最实用的消防知识培训课件(免费) 2
  • 医院开业庆典的祝贺词
  • 人教部编版《乌鸦喝水 》优质公开课教案1
  • OlympusFV1200激光共聚焦显微镜系统操作手册
  • Aspen Plus在加氢裂化尾油低温热利用技术改造中的应用
  • 2018-2019学年北京市*谷区九年级第一学期期末数学试卷(无答案)
  • 电脑版