自己实现spring核心功能 二
2019-08-17 18:00
1571 查看
前言
上一篇我们讲了spring的一些特点并且分析了需要实现哪些功能,已经把准备工作都做完了,这一篇我们开始实现具体功能。
容器加载过程
我们知道,在spring中refesh()方法做了很多初始化的工作,它几乎涵盖了spring的核心流程
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //刷新之前的准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置 prepareRefresh(); //由子类去刷新BeanFactory(如果还没创建则创建),并将BeanFactory返回 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //准备BeanFactory以供ApplicationContext使用 prepareBeanFactory(beanFactory); try { //子类可通过格式此方法来对BeanFactory进行修改 postProcessBeanFactory(beanFactory); //实例化并调用所有注册的BeanFactoryPostProcessor对象 invokeBeanFactoryPostProcessors(beanFactory); //实例化并调用所有注册的BeanPostProcessor对象 registerBeanPostProcessors(beanFactory); //初始化MessageSource initMessageSource(); //初始化事件广播器 initApplicationEventMulticaster(); //子类覆盖此方法在刷新过程做额外工作 onRefresh(); //注册应用监听器ApplicationListener registerListeners(); //实例化所有non-lazy-init bean finishBeanFactoryInitialization(beanFactory); //刷新完成工作,包括初始化LifecycleProcessor,发布刷新完成事件等 finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
做的东西比较复杂,而我们实现做些基本的就好了。
我们在CJDispatcherServlet 类的init方法中,实现如下业务逻辑,就能将spring功能给初始化了,就可以使用依赖注入了
@Override public void init(ServletConfig config) { //加载配置 //获取要扫描的包地址 //扫描要加载的类 //实例化要加载的类 //加载依赖注入,给属性赋值 //加载映射地址 }
加载配置
String contextConfigLocation = config.getInitParameter("contextConfigLocation"); loadConfig(contextConfigLocation);
这里会获取到web.xml中init-param节点中的值
public interface IHomeService { String sayHi(); String getName(Integer id,String no); String getRequestBody(Integer id, String no, GetUserInfo userInfo); } public interface IStudentService { String sayHi(); }View Code
实现类:
@JCService public class StudentService implements IStudentService{ @Override public String sayHi(){ return "Hello world!"; } }View Code
@JCService public class HomeService implements IHomeService{ @JCAutoWrited StudentService studentService; @Override public String sayHi() { return studentService.sayHi(); } @Override public String getName(Integer id,String no) { return "SB0000"+id; } @Override public String getRequestBody(Integer id, String no, GetUserInfo userInfo) { return "userName="+userInfo.getName()+" no="+no; } }View Code
依赖实体:
public class GetUserInfo { public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public BigDecimal getGrowthValue() { return growthValue; } public void setGrowthValue(BigDecimal growthValue) { this.growthValue = growthValue; } private String name; private Integer age; private BigDecimal growthValue; }View Code
加载依赖注入,给属性赋值
//加载依赖注入,给属性赋值 doAutoWrited();
现在我们实现依赖注入,需要定义一个无参的方法doAutoWrite
void doAutoWrited() { for (Map.Entry<String, Object> obj : ioc.entrySet()) { try { for (Field field : obj.getValue().getClass().getDeclaredFields()) { if (!field.isAnnotationPresent(JCAutoWrited.class)) { continue; } JCAutoWrited autoWrited = field.getAnnotation(JCAutoWrited.class); String beanName = autoWrited.value(); if ("".equals(beanName)) { beanName = field.getType().getSimpleName(); } field.setAccessible(true); field.set(obj.getValue(), ioc.get(firstLowerCase(beanName))); } } catch (IllegalAccessException e) { e.printStackTrace(); } } }
这个方法是通过循环ioc里面的实体,反射找出字段,看看是否有需要注入的标记JCAutoWrited,如果加了标记,就反射给字段赋值,类型从ioc容器中获取
加载映射地址
//加载映射地址 doRequestMapping();
映射地址的作用是根据请求的url匹配method方法
void doRequestMapping() { if (ioc.isEmpty()) { return; } for (Map.Entry<String, Object> obj : ioc.entrySet()) { if (!obj.getValue().getClass().isAnnotationPresent(JCController.class)) { continue; } Method[] methods = obj.getValue().getClass().getMethods(); for (Method method : methods) { if (!method.isAnnotationPresent(JCRequestMapping.class)) { continue; } String baseUrl = ""; if (obj.getValue().getClass().isAnnotationPresent(JCRequestMapping.class)) { baseUrl = obj.getValue().getClass().getAnnotation(JCRequestMapping.class).value(); } JCRequestMapping jcRequestMapping = method.getAnnotation(JCRequestMapping.class); if ("".equals(jcRequestMapping.value())) { continue; } String url = (baseUrl + "/" + jcRequestMapping.value()).replaceAll("/+", "/"); urlMapping.put(url, method); System.out.println(url); } } }
这里其实就是根据对象反射获取到JCRequestMapping上面的value值
@JCRequestMapping("/sayHi")
取到的就是/sayHi
另外注意的是:黄色部分使用的变量是一个hashMap,在类上半部分定义的
private Map<String, Method> urlMapping = new HashMap<>();
这里面存的是 url 和对应的method对象。后面处理请求的时候要使用到的。
结尾
容器的初始化到这里就结束了,一共使用了4个容器来存放相关对象,后续servlet处理请求的时候会用到它们。
下一篇,将会继续完善它,通过请求来验证是否可以达到预期效果。另外会实现参数绑定,能处理各类请求并响应。
相关文章推荐
- 自己实现spring的注解扫描处理功能
- Spring核心学习(1)实现基本的容器-包括注入和获取功能
- 分析Spring启动过程,完成实现核心的两大功能(IOC , AOP);
- 自己实现spring核心IOC部分
- 本人用SPRING 框架自己写DAO实现LIMIT功能
- 如何自己实现spring aop相似的功能
- Android高级控件(二)——SurfaceView实现GIF动画架包,播放GIF动画,自己实现功能的初体现
- 自己写的php curl库实现整站克隆功能
- 正方教务系统课表成绩抓取核心代码解析,你也能实现超级课程表的功能
- 读取Spring配置文件 main方法里面测试实现功能
- Android 打造自己的个性化应用(二):应用程序内置资源实现换肤功能
- Android应用如何监听自己是否被卸载及卸载反馈功能的实现(第二版)
- 网上摸索,自己修改实现上传图片的功能
- 【C++语言实现】【本科实验系列】编写程序在CirCle类中实现关系运算符(大于,小于,等于),实现按半径对Circle对象排序,自己定义类中所需成员。完成上述功能。
- Spring实现JavaMail邮件发送功能
- spring和mybatis框架中实现文件下载功能
- springmvc+mybatis+sql server实现简单登录功能【转】
- Spring AOP 实现日志记录功能
- Spring(16):新增功能:在超市订单系统中实现订单表的查询(采用MapperFactoryBean)
- 构造自己的动画函数:animation,stop功能的实现