相关文章:
Spring5 - 30个类手写实战 - 打卡第一天(V1版本)
Spring5 - 30个类手写实战 - 打卡第三天(MVC)
Spring5 - 30个类手写实战 - 打卡第四天(AOP)
Spring5 - 30个类手写实战 - 打卡第五天(手绘IOC时序图)
1.IOC中三个最重要的类
- BeanDefinition : 所有配置文件(properties/xml/yml/…),在内存中的体现形式
- BeanWrapper : 保存了原生对象对未来要创建的各种对象之间的关联关系
- ApplicationContext : 简单的理解为它就是工厂类,它有一个getBean()的方法,从IOC容器中去获取一个实例。Spring中默认是单例,并且是延时加载(Lazy)的。Spring中发生DI由getBean()触发。调用getBean()创建对象。
- BeanDefinitionReader : 读取配置文件,最终将配置文件变成BeanDefinition
今天主要完成以下5个步骤:
- 调用serverlet init() 方法,初始化ApplicationContext
- 读取配置文件 (properties/xml/yml)
- 扫描相关的类 ,配置文件保存到内存中 BeanDefinition
- 初始化IOC容器并且实例化对象 BeanWrapper
- 完成DI注入
项目结构:
2 代码
LBeanDefinition
package com.liulin.spring.framework.beans.config;
/**
* Create by DbL on 2020/5/1 0001
*/
public class LBeanDefinition {
private String beanClassName;
private String factoryBeanName;
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
}
public String getFactoryBeanName() {
return factoryBeanName;
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
}
LBeanWrapper
package com.liulin.spring.framework.beans;
/**
* Create by DbL on 2020/5/1 0001
*/
public class LBeanWrapper {
private Object wrapperInstance;
private Class<?> wrappedClass;
public LBeanWrapper(Object instance) {
this.wrapperInstance = instance;
this.wrappedClass = instance.getClass();
}
public Object getWrapperInstance() {
return wrapperInstance;
}
public Class<?> getWrappedClass() {
return wrappedClass;
}
}
LBeanDefinitionReader
package com.liulin.spring.framework.support;
import com.liulin.spring.framework.beans.config.LBeanDefinition;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* Create by DbL on 2020/5/1 0001
*/
public class LBeanDefinitionReader {
// 保存扫描的结果
private List<String> registryBeanClasses = new ArrayList<String>();
private Properties contextConfig = new Properties();
public LBeanDefinitionReader(String... configLocations) {
// 现在只有一个 写死取第一个
doLoadConfig(configLocations[0]);
// 扫描配置文件中配置的相关的类
doScanner(contextConfig.getProperty("scanPackage"));
}
public List<LBeanDefinition> loadBeanDefinitions() {
List<LBeanDefinition> result = new ArrayList<LBeanDefinition>();
for (String className : registryBeanClasses) {
try {
Class<?> beanClass = Class.forName(className);
if(beanClass.isInterface()){
continue;
}
// 保存类对应的ClassName(全类名) 还有beanName
// 1. 默认类名首字母小写
result.add(doCreateBeandefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));
// 2. 自定义
// 3. 接口注入
for(Class<?> i : beanClass.getInterfaces()){
result.add(doCreateBeandefinition(i.getName(),beanClass.getName()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
private LBeanDefinition doCreateBeandefinition(String beanName, String beanClassName) {
LBeanDefinition beanDefinition = new LBeanDefinition();
beanDefinition.setBeanClassName(beanClassName);
beanDefinition.setFactoryBeanName(beanName);
return beanDefinition;
}
private void doLoadConfig(String contextConfigLocation) {
// Spring中使用策略模式读取,这里直接将classpath: 替换成空
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replaceAll("classpath:", ""));
try {
contextConfig.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != resourceAsStream) {
try {
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void doScanner(String scanPackage) {
// com.liulin.demo 需要转换成文件夹的路径形式便于扫描路径下的文件
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
File classPath = new File(url.getFile());
// 当成是一个classPath文件夹
for (File file : classPath.listFiles()) {
if (file.isDirectory()) {
// 递归遍历子文件夹
doScanner(scanPackage + "." + file.getName());
} else {
// 非class文件跳过
if (!file.getName().endsWith(".class")) continue;
String className = file.getName().replace(".class", "");
// Class.forName(className)
// 防止名字重复,这里使用包名加上类名
registryBeanClasses.add(scanPackage + "." + className);
}
}
}
/**
* 首字母小写
* @param simpleName
* @return
*/
private String toLowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
LApplicationContext
package com.liulin.spring.framework.context;
import com.liulin.spring.framework.annotation.LAutowired;
import com.liulin.spring.framework.annotation.LController;
import com.liulin.spring.framework.annotation.LService;
import com.liulin.spring.framework.beans.LBeanWrapper;
import com.liulin.spring.framework.beans.config.LBeanDefinition;
import com.liulin.spring.framework.support.LBeanDefinitionReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 职责:完成Bean的创建和DI
* Create by DbL on 2020/5/1 0001
*/
public class LApplicationContext {
private LBeanDefinitionReader reader;
private Map<String, LBeanDefinition> beanDefinitionMap = new HashMap<String, LBeanDefinition>();
private Map<String, LBeanWrapper> factoryBeanInstanceCache = new HashMap<String, LBeanWrapper>();
private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();
public LApplicationContext(String... configLocations) {
// 1.加载配置文件
reader = new LBeanDefinitionReader(configLocations);
try {
// 2.解析配置文件,封装成BeanDefinition
List<LBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
// 3.把Beandefinition缓存起来
// beanDefinitionMap
doRegistBeanDefinition(beanDefinitions);
doAutoWrited();
} catch (Exception e) {
e.printStackTrace();
}
}
private void doAutoWrited() {
// 调用getBean() 仅非延时加载的类
for (Map.Entry<String, LBeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
String beanName = beanDefinitionEntry.getKey();
getBean(beanName);
}
}
private void doRegistBeanDefinition(List<LBeanDefinition> beanDefinitions) throws Exception {
for (LBeanDefinition beanDefinition : beanDefinitions) {
if (this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())) {
throw new Exception("The " + beanDefinition.getFactoryBeanName() + " is Exists");
}
beanDefinitionMap.put(beanDefinition.getFactoryBeanName(), beanDefinition);
beanDefinitionMap.put(beanDefinition.getBeanClassName(), beanDefinition);
}
}
// Bean的实例化,DI是从这个方法开始的
public Object getBean(String beanName) {
// 1. 先拿到BeanDefinition配置信息
LBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
// 2.反射实例化 newInstance()
Object instance = instantiateBean(beanName, beanDefinition);
// 3.封装成beanWrapper
LBeanWrapper beanWrapper = new LBeanWrapper(instance);
// 4.保存到IOC容器
factoryBeanInstanceCache.put(beanName, beanWrapper);
// 5.执行依赖注入
populateBean(beanName, beanDefinition, beanWrapper);
return beanWrapper.getWrapperInstance();
}
private void populateBean(String beanName, LBeanDefinition beanDefinition, LBeanWrapper beanWrapper) {
// 可能会涉及到循环依赖? 这里不做处理
// 用两个缓存
// 1.把第一次读取结果为空的BeanDefinition存到第一个缓存
// 2.等第一次循环之后,第二次循环再检查第一次的缓存。再进行赋值
Object instance = beanWrapper.getWrapperInstance();
Class<?> clazz = beanWrapper.getWrappedClass();
// Spring中为component ,为其他注解的父类,这里只针对自定义的LController与LService两个注解
if(!(clazz.isAnnotationPresent(LController.class) || clazz.isAnnotationPresent(LService.class)) ){
return;
}
for (Field field : clazz.getDeclaredFields()) {
if (!field.isAnnotationPresent(LAutowired.class)) {
return;
}
LAutowired autowired = field.getAnnotation(LAutowired.class);
// 如果用户没有自定义的beanName,就默认根据类型注入
String autoWiredName = autowired.value().trim();
if ("".equals(autoWiredName)) {
// 接口全名
autoWiredName = field.getType().getName();
}
// 对于类中的private属性的成员进行暴力访问
field.setAccessible(true);
try {
if(this.factoryBeanInstanceCache.get(autoWiredName) == null){
continue;
}
// ioc.get(beanName) 相当于通过接口的全名从IOC中拿到接口的实现的实例
field.set(instance, this.factoryBeanInstanceCache.get(autoWiredName).getWrapperInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
// 创建真正的实例对象
private Object instantiateBean(String beanName, LBeanDefinition beanDefinition) {
String className = beanDefinition.getBeanClassName();
Object instance = null;
try {
if(this.factoryBeanObjectCache.containsKey(beanName)){
instance = factoryBeanObjectCache.get(beanName);
}else {
Class<?> aClass = Class.forName(className);
instance = aClass.newInstance();
this.factoryBeanObjectCache.put(beanName, instance);
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
public Object getBean(Class beanClass) {
return getBean(beanClass.getName());
}
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
public String[] getBeanDefinitionNames() {
return this.beanDefinitionMap.keySet().toArray(new String[getBeanDefinitionCount()]);
}
}
LDispatcherServlet
package com.liulin.spring.framework.beans.webmvc.servlet;
import com.liulin.spring.framework.annotation.*;
import com.liulin.spring.framework.context.LApplicationContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
/**
* Create by DbL on 2020/4/29 0029
*/
public class LDispatcherServlet extends HttpServlet {
private LApplicationContext applicationContext;
// IOC容器,key默认是类名首字母小写,value是对应的实例对象
// private Map<String, Object> ioc = new HashMap<String, Object>();
private Map<String, Method> handlerMapping = new HashMap<String, Method>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 6.委派,根据URL去找到一个对应的Method并通过response返回
try {
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Exception , Detail : " + Arrays.toString(e.getStackTrace()));
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
if (!this.handlerMapping.containsKey(url)) {
resp.getWriter().write("404 Not Found !!!");
return;
}
Map<String, String[]> params = req.getParameterMap();
Method method = this.handlerMapping.get(url);
// 获取形参列表
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] paramValues = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Class paramterType = parameterTypes[i];
if (paramterType == HttpServletRequest.class) {
paramValues[i] = req;
} else if (paramterType == HttpServletResponse.class) {
paramValues[i] = resp;
} else if (paramterType == String.class) {
// 通过运行时的状态去拿到注解的值
Annotation[][] pa = method.getParameterAnnotations();
for (int j = 0; j < pa.length; j++) {
for (Annotation a : pa[j]) {
if (a instanceof LRequestParam) {
String paramName = ((LRequestParam) a).value();
if (!"".equals(paramName.trim())) {
String value = Arrays.toString(params.get(paramName))
.replaceAll("\\[|\\]", "")
.replaceAll("\\s+", "");
paramValues[i] = value;
}
}
}
}
}
}
String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
method.invoke(applicationContext.getBean(beanName), paramValues);
}
@Override
public void init(ServletConfig config) throws ServletException {
// 初始化Spring的核心IO容器
applicationContext = new LApplicationContext(config.getInitParameter("contextConfigLocation"));
//================MVC部分==============//
// 5.初始化HandlerMapping
doInitHandlerMapping();
System.out.println("L Spring framework init success ");
}
private void doInitHandlerMapping() {
if (this.applicationContext.getBeanDefinitionCount() == 0) {
return;
}
for (String beanName : this.applicationContext.getBeanDefinitionNames()) {
Class<?> clazz = applicationContext.getBean(beanName).getClass();
// 类没有加注解的跳过
if (!clazz.isAnnotationPresent(LController.class)) {
continue;
}
// 如果类上定义了路径,方法上的路径需要拼接上此路径
String baseUrl = "";
if (clazz.isAnnotationPresent(LRequestMapping.class)) {
LRequestMapping Mapping = clazz.getAnnotation(LRequestMapping.class);
baseUrl = Mapping.value();
}
// 只获取public的方法
for (Method method : clazz.getMethods()) {
// 方法没有加注解的跳过
if (!method.isAnnotationPresent(LRequestMapping.class)) {
continue;
}
LRequestMapping requestMapping = method.getAnnotation(LRequestMapping.class);
// 对于配置了“/” 和没有配置“/”的通过正则表达式统一处理
String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
handlerMapping.put(url, method);
System.out.println("mapped : " + url + " , " + method);
}
}
}
/**
* 首字母小写
* @param simpleName
* @return
*/
private String toLowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}