Spring框架对于java开发者来说是不可缺少的,如今我们接触到的项目几乎都不开spring,我们整天都在使用spring,例如@Controller、@Autowired、@Autowired、@RequestMapping,我相信大部分都能知道它的作用,同时我也希望能本文能帮助到你更深的了解他们。
前言记录文章目的及意义在于为了自己知识的巩固,当然也十分希望在此能够得到业界前辈们的指导。 若有不正确的地方,希望能够及时批评指正。首先在此感谢
本篇内容本篇文章的内容,主要对于springMVC的配置阶段、初始化阶段、运行阶段做些粗浅的学习记录。围绕着@Controller、@Autowired、@Autowired、@RequestMapping来实现功能。 方式:手写一个简单的mvc。
一、准备介绍一下mvc的基本实现思路,先介绍然后在编码。
1.1、配置阶段我们都知道SpringMVC的本质就是从Servlet演变而来,它继承自HttpServlet,通常在使用Servlet的时候,我们都会去配置Web.xml文件,其实所有依赖于web容器的项目,都是从读取web.xml文件开始的。 web.xml:
MVC Web Application
CcMvc
com.ccc.mvcframework.v1.setvlet.CccDispatcherServletTest
contextConfigLocation
classpath:application.properties
configFile
application.properties
1
CcMvc
/*
以上作用: 1.指定DispathcerServlet 2.配置ServletMapping(url路径) 3.如果是与spring一块使用我们还会指定spring.xml配置文件. 当然web.xml的功能远远不止于此,在这里咱就介绍几个关键的。
1.2初始化阶段此阶段主要分为六个步骤: 1.加载配置文件(web.xml中的param-value). 2.通过配置文件扫描相关的类(.class结尾的文件)。 3.筛选出带有注解的类并放入到IOC容器中.(控制反转,注解的类:@controller@Service等) 4.扫描IOC容器中的实例,给没有复制的属性自动复制(DI依赖注入) 5.初始化HandlerMapping,将url和方法对应起来。 到此初始化过程大致完成。
1.3运行阶段1.doPost()/doGet():获取到request/response对象。 2.从HandlerMapping匹配到request中的url,找到对应的方法。 3.反射调用该方法。 4.返回数据。 贴一张配置文件的内容:application.properties,只有一行
scanPackage=com.ccc.mvcframework.v1.demo
二、编码提醒一下,记得web.xml文件哦,由于前文介绍到了这里就不在介绍了。
2.1定义注解2.1.1 Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XHController {
String value() default "";
}
2.1.2 Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XHService {
String value() default "";
}
2.1.3 Autowired
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XHAutowired {
String value() default "";
}
2.1.4 RequestMapping
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XHRequestMapping {
String value() default "";
}
2.1.5 RequestParam
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XHRequestParam {
String value() default "";
}
解释一下定义注解: 定义一个最基本的注解包含了两个步骤:1、注解的名字;2、注解包含的类型。 如: 1.@Target :限定某个自定义注解能够被应用在哪些Java元素上面的.是一个数组类型。它使用的是一个枚举(ElementType)类型定义. ElementType:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
/** 类,接口(包括注解类型)或枚举的声明*/
TYPE,
/** Field declaration (includes enum constants) */
/** 属性的声明 */
FIELD,
/** Method declaration */
/** 方法的声明 */
METHOD,
/** Formal parameter declaration */
/** 方法形式参数声明 */
PARAMETER,
/** Constructor declaration */
/** 构造方法的声明 */
CONSTRUCTOR,
/** Local variable declaration */
/** 局部变量声明 */
LOCAL_VARIABLE,
/** Annotation type declaration */
/** 注解类型声明 */
ANNOTATION_TYPE,
/** Package declaration */
/** 包的声明 */
PACKAGE,
/**
* Type parameter declaration
* 类型参数声明
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*类型的使用
* @since 1.8
*/
TYPE_USE
}
2.@Retention声明注解在什么时候生效.同样是以枚举类型来声明。这里就不展示源码了为了节省位置。 主要有3个: 1.SOURCE:源文件阶段(声明为此阶段生效也就是只在源文件中生效,不参与编译与运行类似于注释效果) 2.CLASS:编译到class文件阶段(在编译阶段生效,可以用来处理一些逻辑。不会在运行期生效) 3.RUNTIME:运行期阶段(emmm不用解释了吧,我们用的几乎都是这个。)
2.2定义DispatcherServlet此处就是mvc的核心步骤了。我们将按照前文中介绍的步骤依次来完成。 1.定义一个DispatcherServlet继承自HttpServlet并重写父类的doGet()、doPost()、init()三个方法。 init()方法相信大家都知道此方法会在加载的时候就调用。所以我们初始化的入口就在此。 请看代码: 2.声明一个Properties变量存储配置文件的内容。 3.在init方法中我们按照前文步骤依次声明方法。
public class CccDispatcherServletTest extends HttpServlet {
//存储aplication.properties的配置内容
private Properties contextConfig = new Properties();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
public void init(ServletConfig config) throws ServletException {
//ServletConfig 可以获取web.xml文件的属性
//使用模板模式
//1、加载配置文件
doLoadConfig(config.getInitParameter("configFile"));
//2、扫描相关的类
doScanner(contextConfig.getProperty("scanPackage"));
//3、初始化所有相关的类的实例,并且放入到IOC容器之中
doInstance();
//4、完成依赖注入
doAutowired();
//5、初始化HandlerMapping
initHandlerMapping();
System.out.println("XH Spring framework is init end.");
}
//5、初始化HandlerMapping
private void initHandlerMapping() {
}
//4、完成依赖注入
private void doAutowired() {
}
//2、扫描相关的类
private void doScanner(String scanPackage) {
}
//3、初始化所有相关的类的实例,并且放入到IOC容器之中
private void doInstance() {
}
//1、加载配置文件
private void doLoadConfig(String configFile) {
}
}
2.2.1加载配置文件doLoadConfig()
这里比较简单
private void doLoadConfig(String contextConfigLocation) {
try(InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation)) {
//加载配置文件,此时配置文件已存于内存中了
contextConfig.load(fis);
} catch (Exception e) {
e.printStackTrace();
}
}
2.2.2 扫描相关的类doScanner()
首先声明一个一个集合存储扫描到的类
private List classNames = new ArrayList();
private void doScanner(String scanPackage) {
//scanPackage=com.ccc.mvcframework.v1.demo
//包传过来包下面的所有的类全部扫描进来的,并替换成/路径
URL url = this.getClass().getClassLoader()
.getResource("/" + scanPackage.replaceAll("\\.", "/"));
//获取这个文件
File classPath = new File(url.getFile());
//遍历文件下的数据
for (File file : classPath.listFiles()) {
//如果是一个目录,则递归查找
if (file.isDirectory()) {
doScanner(scanPackage + "." + file.getName());
} else {
//如果是一个.class文件去掉.class后缀存放到集合中,如果不是则跳过此次循环
if (!file.getName().endsWith(".class")) {
continue;
}
String className = (scanPackage + "." + file.getName()).replace(".class", "");
classNames.add(className);
}
}
}
此方法的作用就是找到路径下所有的类文件并存储起来。 解释一下: 1.为什么要用/来替换.呢? 因为我们scanPackage的值是以命名包名的形式来写的,而使用File的话就得换成/的目录形式了。 2.为什么要去掉.class后缀在保存呢? 这里举个例子吧.假设类名className=Test,如果我们通过名字得到这个类对象怎么获取呢?当然是使用反射Class.fromName(className).结果是不是很明显了,我们可以通过Test来得到这个对象,但是不能通过Test.class来得到这个对象。
2.2.3 控制反转doInstance()1.首先声明一个IOC容器用来保存所有实例化对象
private Map ioc = new HashMap();
2.声明一个方法用来进行类名首字母小写.
private String toLowerFirstCase(String simpleName) {
//该方法将字符串转为一个char数组。
char[] chars = simpleName.toCharArray();
/**
* 将首字母往左移32位,1
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?