一直没有记笔记的习惯,就在此时,决定将自己每一次进步都记录下来。经过几次国内大公司面试。目前而言:对java的理解是停留在运用框架和中间件的层次上,对于底层原理并没有深刻去理解。所以让我决定重新学习java的想法。花了一点时间,将springMvc从底层进行了简单分析。从web.xml,配置加载,常用注解,我们将底层重新进行简单的开发,目的了解spring的底层思想。
首先从几个题目出发:
1.什么是spring框架?spring框架有哪些模块?
2.使用spring框架带来什么好处?
3.什么是控制反转?什么是依赖注入?
4.BeanFactory和Application有什么区别?
5.Spring的生命周期?
6.SpringBean各作用域区别?
7.spring单例bean是否线程安全?
8.AOP底层原理?
9.Spring怎么管理事务?
对于以上问题的理解,我认为我们应该动手将spring源码自己敲敲看!看源码最难是思想,然后就找入口。
首先我们分析spring加载过程:我们分三块来理解:
一,配置阶段:
1.web.xml
2.dispatcherServlet->springweb开发入口
3.application.xml
4.url-patten->映射url
二.初始化:
1.init()->有web容器调用servlet初始化
2.加载配置文件
3.初始化IOC容器
4.依赖注入
5.初始化HandlerMapping
三.运行阶段
1.doservice()->用户请求调用
2.request.getUrl->获取url
3.匹配url对应的方法
4.调用method
5.利用response返回web
下面我们通过 上面的步骤,我们将springMvc重新开发一遍。
工程结构:
web.xml:
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
package com.iflytek.spring.controller;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;
import com.iflytek.spring.annotation.IflytekAutowrited;
import com.iflytek.spring.annotation.IflytekController;/**
* 一个非常简单的Controller
}
package com.iflytek.spring.service;
/**
* 定义一个接口
*
* @author: [email protected]
* @created:Apr 6, 2018 8:10:06 PM
* @version: 1.0
* @lastModified
*/
public interface ISpringService {
public String query(String id);
}
package com.iflytek.spring.service;
import com.iflytek.spring.annotation.IflytekService;
/**
* 实现类
* @author: [email protected]
* @created:Apr 6, 2018 8:10:28 PM
* @version: 1.0
* @lastModified
*/
@IflytekService
public class SpringServiceImpl implements ISpringService{
public String query(String id) {
return id;
}
}
下面我们将注解重新开发:
package com.iflytek.spring.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
package com.iflytek.spring.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Autowrited注解
* @author: [email protected]
* @created:Apr 6, 2018 8:06:35 PM
* @version: 1.0
* @lastModified
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekAutowrited {
String value() default "";
}
package com.iflytek.spring.annotation;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @Controller注解
* @author: [email protected]
* @created:Apr 6, 2018 8:04:52 PM
* @version: 1.0
* @lastModified
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekController {
String value() default "";
}
package com.iflytek.spring.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @RequestMapping注解
* @author: [email protected]
* @created:Apr 6, 2018 8:07:40 PM
* @version: 1.0
* @lastModified
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekRequestMapping {
String value() default "";
}
package com.iflytek.spring.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @RequestParam注解
* @author: [email protected]
* @created:Apr 6, 2018 8:08:20 PM
* @version: 1.0
* @lastModified
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekRequestParam {
String value() default "";
}
package com.iflytek.spring.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Service注解
* @author: [email protected]
* @created:Apr 6, 2018 8:05:44 PM
* @version: 1.0
* @lastModified
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IflytekService {
String value() default "";
}
package com.iflytek.spring.servlet;
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.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.iflytek.spring.annotation.IflytekAutowrited;
import com.iflytek.spring.annotation.IflytekController;
import com.iflytek.spring.annotation.IflytekRequestMapping;
import com.iflytek.spring.annotation.IflytekRequestParam;
import com.iflytek.spring.annotation.IflytekService;
/**
* @author: [email protected]
* @created:Apr 6, 2018 8:32:12 PM
* @version: 1.0
* @lastModified
*/
public class IflytekDisPatcherSevlet extends HttpServlet {
// 配置文件
private Properties properties = new Properties();
// 所有类名
private List
// ioc中容器的实例
private Map
// 请求方法映射
// private Map
private List
/**
* 初始化
*/
@Override
public void init(ServletConfig config) throws ServletException {
// 1.加载配置文件
doloadConfig(config.getInitParameter("contextConfigLocation"));
// 2.根据配置文件扫描所有的类
doScaner(properties.getProperty("scanPackage"));
// 3.初始化所有类实例,放入ioc容器,也就是放入Map
try {
doIntance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// 4.实现自动依赖注入
doAutowried();
// 5.初始化mapping
initHandleMapping();
}
private void initHandleMapping() {
String baseUrl = null;
if (ioc.isEmpty()) {
return;
}
for (Map.Entry
Class> clazz = entry.getValue().getClass();
// 不是Controller-就拜拜
if (!clazz.isAnnotationPresent(IflytekController.class)) {
continue;
}
// 判断有没有@IflytekRequestMapping注解
if (clazz.isAnnotationPresent(IflytekRequestMapping.class)) {
IflytekRequestMapping requestMapping = clazz.getAnnotation(IflytekRequestMapping.class);
baseUrl = requestMapping.value();
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 方法上如果没有加@IflytekRequestMapping
if (!method.isAnnotationPresent(IflytekRequestMapping.class)) {
continue;
}
IflytekRequestMapping requestMapping = method.getAnnotation(IflytekRequestMapping.class);
// String url = (baseUrl +
// requestMapping.value()).replaceAll("/+", "/");
String regex = ("/" + baseUrl + requestMapping.value()).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
handlerMapping.add(new Handler(pattern, entry.getValue(), method));
}
}
}
private void doAutowried() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry
// 无论是什么访问权限,都要强制注入
Field[] fields = entry.getValue().getClass().getDeclaredFields();// 获取对象的所有属性
for (Field field : fields) {
// 判断字段上有没有@Autowried注解,有的话才注入
if (!field.isAnnotationPresent(IflytekAutowrited.class)) {
continue;
}
IflytekAutowrited autowrited = field.getAnnotation(IflytekAutowrited.class);
// 获取注解上有没有自定义值
String beanName = autowrited.value().trim();
// 如果没有自定义值,也就是null
if ("".equals(beanName)) {
beanName = field.getType().getName();
}
// 如果想要访问到私有的属性,我们要强制授权
// 不管你愿不愿意,我们都要给你注入
field.setAccessible(true);
try {
// 给@Autowrid设上了值
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
field.set(entry.getValue(), ioc.get(beanName));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void doIntance() throws InstantiationException, IllegalAccessException {
if (calssNames != null)
// 通过反射机制构造对象
for (String calssName : calssNames) {
try {
Class> calzz = Class.forName(calssName);
// 初始化Ioc容器
// 只有头上有注解的才构造对象
// IOC key:
// value原则:
// 1.key默认类名小写
// 2.如果自定义了类名,则优先使用(@Service("AAA"))
// 3.如果注入是接口我们可以巧妙的用接口的类型作为key
if (calzz.isAnnotationPresent(IflytekController.class)) {
String className = calzz.getSimpleName();// 得到类名
String baneName = firstLowerCase(className);// 类名小写
ioc.put(baneName, calzz.newInstance());// 将反射生成的对象放入ioc容器
} else if (calzz.isAnnotationPresent(IflytekService.class)) {
IflytekService sevice = calzz.getAnnotation(IflytekService.class);
String beanNme = sevice.value();
// 如果自定义名称为空,就是默认首字母小写
if ("".equals(beanNme.trim())) {
beanNme = firstLowerCase(calzz.getSimpleName());// 类名小写
}
Object instance = calzz.newInstance();
ioc.put(beanNme, instance);
Class>[] interfaces = calzz.getInterfaces();
// 2.如果自定义了类名,则优先使用(@Service("AAA"))
for (Class> iface : interfaces) {
// 如果注入是接口我们可以巧妙的用接口的类型作为key
ioc.put(iface.getName(), instance);
}
} else {
continue;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// 类名首字母转小写(此种方法高效)
private String firstLowerCase(String className) {
System.out.println(className + "-----className------");
char[] chars = className.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
private void doScaner(String packageName) {
// 递归扫描所有的类
URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
File classDir = new File(url.getFile());
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {
doScaner(packageName + "." + file.getName());
} else {
String className = packageName + "." + file.getName().replace(".class", "");
calssNames.add(className);
}
}
}
private void doloadConfig(String config) {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(config);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req, resp);
} catch (Exception e) {
resp.getWriter().write("500 Server Exception");
e.printStackTrace();
}
}
// 等待请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取用户请求uri
// String url = req.getRequestURI();
// String contextPath = req.getContextPath();
// url = url.replace(contextPath, "").replaceAll("/+", "/");//
// replaceAll("/+",
// "/")表示把多个/一个转为(//-->/)
// 通过请求的url获取到要映射的方法
// if (!handlerMapping.containsKey(url)) {
// resp.getWriter().write("404 Not Found");
// return;
// }
// Method method = handlerMapping.get(url);
// method.invoke(obj, args);
// 获取method Url配置
try {
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
private class Handler {
protected Object controller;
protected Method method;
protected Pattern pattern;
protected Map
public Handler(Pattern pattern, Object controller, Method method) {
this.pattern = pattern;
this.controller = controller;
this.method = method;
this.paramIndexMaping = new HashMap
putParamIndexMaping(method);
}
private void putParamIndexMaping(Method method) {
// 提取方法中加了注解的参数
Annotation[][] pa = method.getParameterAnnotations();
for (int i = 0; i < pa.length; i++) {
for (Annotation annotation : pa[i]) {
if (annotation instanceof IflytekRequestParam) {
String paramName = ((IflytekRequestParam) annotation).value();
if (!"".equals(paramName.trim())) {
paramIndexMaping.put(paramName, i);
}
}
}
}
Class>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class> type = parameterTypes[i];
if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
paramIndexMaping.put(type.getName(), i);
}
}
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
try {
Handler handler = getHandler(req);
if (handler == null) {
resp.getWriter().write("404 Not Found");
return;
}
// 获取参数列表
Class>[] parameters = handler.method.getParameterTypes();
// 保存所有自动赋值的参数值
Object[] parameValues = new Object[parameters.length];
Map
for (Entry
String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
// 如果找到匹配的对象,就填充参数
if (!handler.paramIndexMaping.containsKey(param.getKey())) {
continue;
}
int index = handler.paramIndexMaping.get(param.getKey());
parameValues[index] = convert(parameters[index], value);
}
// 设置方法中的 HttpServletRequest HttpServletResponse 对象
int reqIndex = handler.paramIndexMaping.get(HttpServletRequest.class.getName());
parameValues[reqIndex] = req;
int respIndex = handler.paramIndexMaping.get(HttpServletResponse.class.getName());
parameValues[respIndex] = resp;
handler.method.invoke(handler.controller, parameValues);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @content:
* @author: [email protected]
* @created:Apr 7, 2018 1:48:03 AM
* @version: 1.0
* @lastModified
*/
private Object convert(Class> type, String value) {
if (Integer.class == type) {
return Integer.valueOf(value);
}
return value;
}
private Handler getHandler(HttpServletRequest req) {
if (handlerMapping.isEmpty()) {
return null;
}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
// replaceAll("/+","/")表示把多个/一个转为(//-->/)
url = url.replace(contextPath, "").replaceAll("/+", "/");
for (Handler handler : handlerMapping) {
try {
Matcher matcher = handler.pattern.matcher(url);
// 如果没有就继续下一个匹配
if (matcher.matches()) {
continue;
}
return handler;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}