手写Spring框架学习笔记
以下是咕泡公开课的学习笔记
一、创建工程springdemo

二、在pom中配置servlet
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
三、web.xml文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app>
<display-name>Archetype Created Web Application</display-name> <servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>com.example.mvcframework.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
四、资源文件
application.properties文件
scanPackage=com.example.demo
五、创建注解
1、Autowired
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
String value() default "";
}
2、Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
3、RequestMapping
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
4、RequestParam
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
String value() default "";
}
5、Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
六、创建DispatcherServlet
public class DispatcherServlet extends HttpServlet {
private Properties contextConfig = new Properties();
private List<String> classNames = new ArrayList<>();
private Map<String, Object> ioc = new HashMap<>();
private Map<String,Method> handlerMapping = new HashMap<>();
@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 {
//运行阶段,根据用户请求的URL进行自动分发和调度
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Detail:" + Arrays.toString(e.getStackTrace()));
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if(this.handlerMapping.isEmpty()){
return;
}
//绝对路径
String url = req.getRequestURI();
//处理成相对路径
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
if(!this.handlerMapping.containsKey(url)){
resp.getWriter().write("404 Not found");
return;
}
Method method = this.handlerMapping.get(url);
//如何拿到实例?
//唯一的方式从IOC容器中拿
//继续投机取巧
String beanName = lowerFirstCase(method.getDeclaringClass().getSimpleName());
System.out.println("beanName:" + beanName);
Map<String,String[]> params = req.getParameterMap();
method.invoke(ioc.get(beanName), new Object[]{req, resp,params.get("name")[0]});
// System.out.println(method);
}
@Override
public void init(ServletConfig config) throws ServletException {
//1、加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
//2. 扫描所有相关的类
doScanner(contextConfig.getProperty("scanPackage"));
//3.初始化刚刚扫描到所有相关的类,并且把它保存在IOC容器中
doInstance();
//4. 实现依赖注入 DI 自动赋值
doAutowired();
//5. 初始化handlerMapping
initHandleMapping();
System.out.println("Spring is init");
}
private void initHandleMapping() {
if(ioc.isEmpty()){
return;
}
for(Map.Entry<String, Object> entry: ioc.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
if(!clazz.isAnnotationPresent(Controller.class)){
continue;
}
String baseUrl = "";
if(clazz.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
baseUrl = requestMapping.value();
}
Method[] methods = clazz.getMethods(); //只认public的方法
for(Method method : methods){
if(!method.isAnnotationPresent(RequestMapping.class)){
continue;
}
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
handlerMapping.put(url,method);
System.out.println("Mapped:" + url +"," + method);
}
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
}
}
}
private void doAutowired() {
if(ioc.isEmpty()){
return;
}
for(Map.Entry<String, Object> entry: ioc.entrySet()){
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for(Field field: fields){
if(!field.isAnnotationPresent(Autowired.class)){
continue;
}
Autowired autowired = field.getAnnotation(Autowired.class);
String beanName = autowired.value().trim();
if("".equals(beanName)){
beanName = field.getType().getName();
}
field.setAccessible(true); //强制暴力访问
try {
field.set(entry.getValue(), ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
continue;
}
}
}
}
private void doInstance() {
if(classNames.isEmpty()){
return;
}
try{
for (String className: classNames) {
Class<?> clazz = Class.forName(className);
//实例化,把实例化的对象保存到IOC容器之中
if(clazz.isAnnotationPresent(Controller.class)){
Object instance = clazz.newInstance();
String beanName = lowerFirstCase(clazz.getSimpleName());
ioc.put(beanName, instance);
} else if(clazz.isAnnotationPresent(Service.class)){
//因为Service有可能注入的不是它本身,有可能是它的实现类
//1、默认类名首字母小写
//2、自定义的beanName
Service service = clazz.getAnnotation(Service.class);
String beanName = service.value();
if("".equals(beanName)){
beanName = lowerFirstCase(clazz.getSimpleName());
}
Object instance = clazz.newInstance();
ioc.put(beanName, instance);
//3、如果是接口,投机取巧的方式,用它的接口类型作为key
Class<?>[] interfaces = clazz.getInterfaces();
for(Class<?> i : interfaces){
if(ioc.containsKey(i.getName())){
throw new Exception("The beanName is exists");
}
ioc.put(i.getName(), instance);
}
}else{
continue;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 类名首字母小写
*/
private String lowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
File classDir = new File(url.getFile());
for(File file : classDir.listFiles()){
if(file.isDirectory()){
doScanner(scanPackage + "." + file.getName());
}else{
if(file.getName().endsWith(".class")){
String classname = (scanPackage + "." +file.getName()).replace(".class","");
classNames.add(classname);
}
}
}
}
private void doLoadConfig(String contextConfigLocation) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {
contextConfig.load(is);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
七、使用
1、创建接口
public interface IDemoService {
String get(String name);
}
2、创建服务
@Service
public class DemoService implements IDemoService {
@Override
public String get(String name) {
return "hello," + name;
}
}
3、创建Controller
@Controller
@RequestMapping("/demo")
public class DemoAction { @Autowired
private IDemoService demoService; @RequestMapping("/query")
public void query(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name){
String result = demoService.get(name);
try {
resp.getWriter().write(result);
}catch (IOException e){
e.printStackTrace();
}
} @RequestMapping("/add")
public void add(HttpServletRequest req, HttpServletResponse resp, @RequestParam("a")Integer a, @RequestParam("b") Integer b){
try {
resp.getWriter().write(a + "+" + b + "=" + (a+b));
}catch (IOException e){
e.printStackTrace();
}
} @RequestMapping("/remove")
public void remove(HttpServletRequest req, HttpServletResponse resp, @RequestParam("id")Integer id){ }
}
八、测试

九、Spring十大优势
1、面向接口编程
2、IOC容器的问世
3、AOP思想,使得程序员把大部分精力投入到业务
4、Spring生态完善,Spring不仅仅只是一个框架
5、兼容程度高。只要有Java的地方就有Spring的用武之地
6、Spring的模块化拆分的非常精准,避免过度依赖(低耦合)
7、轻量级,所有的操作都建立在JavaBean之上
8、Spring与时俱进,全面支持Annotation,简化配置。如今的Spring可以实现配置裕兴
9、内部工具类非常丰富,简化开发,提升开发效率
10、Spring与各个开源框架可以实现无缝集成(Dubbo框架也是与Spring集成)
核心:提升开发效
手写Spring框架学习笔记的更多相关文章
- Spring框架学习笔记(5)——Spring Boot创建与使用
Spring Boot可以更为方便地搭建一个Web系统,之后服务器上部署也较为方便 创建Spring boot项目 1. 使用IDEA创建项目 2. 修改groupid和artifact 3. 一路n ...
- 手写Spring框架,加深对Spring工作机制的理解!
在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越 ...
- Spring框架学习笔记(8)——spring boot+mybatis plus+mysql项目环境搭建
之前写的那篇Spring框架学习笔记(5)--Spring Boot创建与使用,发现有多小细节没有提及,,正好现在又学习了mybatis plus这款框架,打算重新整理一遍,并将细节说清楚 1.通过I ...
- Spring框架学习笔记(1)
Spring 框架学习笔记(1) 一.简介 Rod Johnson(spring之父) Spring是分层的Java SE/EE应用 full-stack(服务端的全栈)轻量级(跟EJB比)开源框架, ...
- spring框架学习笔记7:事务管理及案例
Spring提供了一套管理项目中的事务的机制 以前写过一篇简单的介绍事务的随笔:http://www.cnblogs.com/xuyiqing/p/8430214.html 还有一篇Hibernate ...
- Spring框架学习笔记(3)——SpringMVC框架
SpringMVC框架是基于Spring框架,可以让我们更为方便的进行Web的开发,实现前后端分离 思路和原理 我们之前仿照SpringMVC定义了一个自定义MVC框架,两者的思路其实都是一样的. 建 ...
- spring框架学习笔记6:JDBC模板
JDBC模板:Spring中对数据库的操作. 这一部分对熟悉DBUtils的QueryRunner的开发者来说,非常简单 这是以前我简单写的dbutils的知识: http://www.cnblogs ...
- spring框架学习笔记1:搭建测试
Spring框架介绍: Spring框架涵盖了web.service.dao三层,本身是一个存放对象的容器 形象来说:Spring是项目中对象管家 Spring框架的两大核心思想:控制反转(IOC). ...
- 手写Spring框架,是时候撸个AOP与Bean生命周期融合了!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 嘎小子,这片代码水太深你把握不住! 在电视剧<楚汉传奇>中有这么一段刘邦 ...
随机推荐
- 漫步Java------初识java
一. Java语言概述 语言:是人与人之间用于沟通的一种方式. 例如:中国人与中国人用普通话沟通.而中国人要和英国人交流,就要学习英语. 计算机语言(编程语言): 人与计算机交流的方式.如果人要与计算 ...
- 分析攻击IP来源地并画出饼图
此文中的API将台湾列为国家,非本人立场,台湾属于中国,台湾岛生活的人不一定! 上码: #!/usr/bin/python #coding=utf-8 ''' http://ip-api.com/js ...
- Java并发容器和框架
ConcurrentHashMap 在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率近100%.因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环 ...
- 河南省第四届ACM省赛(T1) 序号互换
问题 A: 序号互换 时间限制: 1 Sec 内存限制: 128 MB难度1 题目描述 Dr.Kong设计了一个聪明的机器人卡多,卡多会对电子表格中的单元格坐标快速计算出来.单元格的行坐标是由数字编 ...
- Codeforces Round #519
题目链接:传送门 A. Elections (思维+暴力) 思路: 从最小的k开始枚举就好了- -. #include <bits/stdc++.h> using namespace ...
- root/base/stem概念
The verb root (or base form): 1.is the same as the infinitive不定式 (e.g., to dive, to jump, to wonder) ...
- Blender节点笔记
Blender节点笔记实现复杂材质,纹理的更直观的方式就是使用节点功能. 每个节点左边作为输入,右边作为输出.节点之间通过传递值影响后者.传递的值为(Scalars,Vectors)标量与矢量.二维矢 ...
- mysql中不直接通过密码连接 还要指定ip地址进行连接----------DCL数据库控制语言
线上如果用root超级用户连接数据库,非常容易造成隐私泄漏.一般线上不用root数据控制. 今天和大家分享的是 输入密码还不可以连接数据库,必须要输入ip地址以后,才可以连接. 正常的访问数据库都是 ...
- 【BZOJ1202】【HNOI2005】狡猾的商人
查分约束好,好写好调好AC! 原题: 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1, ...
- vue全家桶+Koa2开发笔记(8)--开发网页
1.使用 mongoose 动态倒入数据 mongoimport -d student -c areas areas.dat -d 后面是数据库名称: -c后面是表名称 最后是数据源 2.使用vue的 ...