反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
多数情况下反射是为了提高程序的灵活性,运行时动态加载需要加载的对象。
SpringBoot之Controller用法
Controller
Controller是SpringBoot里最基本的组件,他的作用是把用户提交来的请求通过对URL的匹配,分配给不同的接收器,再进行处理,然后向用户返回结果。他的重点就在于如何从HTTP请求中获得信息,提取参数,并分发给不同的处理服务。
基本组成
一个最经典的Controller应该大概长这样:
1 | package com.example.demo.controller; |
首先应该在类的开头,加上@Controller
注解,告知Spring这是一个控制器。
然后在对应的处理函数前面加上@RequestMapping
,告知这个函数需要相应的URL。
接着这个函数传入了一个Model类型的参数,这个参数主要是用于向模板传递数据。
该函数最后返回了一个叫”index”的字符串,表示将调用名为”index”的模板,具体名称取决于模板引擎,比如对于jsp他将访问”index.jsp”这个文件,对于thymeleaf,他将访问”index.html”这个文件。
上面的是最简单的用法,实际上有很多细节需要注意,下面就来一一解释。
ResponseBody
如果我们想返回纯字符串而不是渲染后的模板,那我们可以在需要返回字符串的函数前面加上@ResponseBody
这个注解;
如果我们像对于整个类都返回字符串,我们也可以在这个类前面加上@ResponseBody
注解,或者将@Controller
注解换成@RestController
,均可。
RequestMapping
基本用法
这个注解是用来告诉Spring,下面的这个函数或者类是用来映射到那个URL的,通常情况下有下面这些选项:
1 | @RequestMapping( |
我们可以指定这个路径,参数,方法,头信息,来作为一个Controller的入口。当然,通常我们只需要指定path就行了。
对象转json或xml
这里有一个使用的小窍门,比如有时候我们希望返回json字符串,我们当然可以调用jackson,gson,fastjson等等工具来组合数据,但是这样显然比较麻烦。其实springboot自带了将对象持久化的工具,只要我们在produces
参数中指定头信息,就可以将返回的对象直接转换为json或xml。比如:
1 | package com.mythsman.controller; |
访问后的返回结果就是{"name":"myths","age":12}
。同理,也可以自动转换成xml格式,不过xml格式对与map等的数据结构无法支持,因此我们还是建议采用json。
作用对象
这个注解可以注解一个函数,也可以注解一个类。当注解一个类时,类中所有的方法都会在这个基础上再进行过滤:
1 | @Controller |
这个函数就能匹配”/path1/path1”这个地址。
缺省参数
当RequestMapping的参数是空的时候,他就表示匹配剩余所有的页面,实际上也就是匹配所有的404页面。
1 | @Controller |
当RequestMapping不指定参数名时,默认就是path参数。
1 | @Controller |
PathVariable
RequestMapping中的path也可以是一个未定的变量,比如下面的代码:
1 | @Controller |
通过花括号我们就可以指定这个变量,并且通过@PathVariable
注解得到这个参数,非常方便。
RequestParam
RequestMapping也可以获取类似表单传回的信息形式,比如/index?name=XXX
,这个name
变量就可以通过RequestParam注解来获得:
1 | @Controller |
我们可以控制这个参数的名字,是否必须,以及设置默认值,来更好的进行匹配。
RequestBody
RequestBody用来获取Post信息的消息体,只要在参数中通过@RequestBody
注解就能得到这个参数:
1 | @Controller |
总结
上面这些大概就是Controller中最基本的用法了,十分的方便清楚。具体的细节可以参考源码中的注释,解释的也是十分详尽了。
SpringBoot环境熟悉
前言
就个人而言,我曾经比较畏惧JAVA,我们都知道JAVA这个东西是相当成熟了,各种框架特别复杂,名词也特别的多。我还记得我第一次想学struts的时候折腾了半天硬是没有找到头绪,面对各种眼花缭乱的包、眼花缭乱的配置文件、眼花缭乱的框架版本、眼花缭乱的报错信息,还有眼花缭乱的各种名词,硬是停留在了servlet的层面上,完全失去了在短时间内学下去的动力。因此很久都没有碰过JAVA。不过一个机缘巧合,我突然发现其实这些东西都是很有套路的,每一个东西其实都是为了解决某一个小问题,只是刚入门的时候面对庞大的体系一下子懵了。而且,在JAVA发展到当今的程度,之前冗杂的事情也被简化了很多,框架的封装度更加的高,我们学起来也轻松很多了。
SpringBoot
Springboot就是当前火热起来的用于JAVA Web开发的微框架,配置十分方便,结合Intellij IDEA用起来十分的顺手,非常适合快速上手。同时他的文档也清楚,官方文档里写的也很细致。
快速上手
曾经最烦人的配置问题在这里都不是问题,当我们需要创建项目的时候,可以去start.spring.io上选择相应的配置,下载一个空的项目包,然后用IDE打开即可。
通常情况下,除了指定包信息以及各种版本信息之外,我们在开发Springboot的时候一般会加上下面的依赖:
- Thymeleaf
- AOP
- MySQL
- MyBatis
- Redis
- DevTools
Thymeleaf是SpringBoot1.5版本后推荐的模板引擎,取代了曾经的velocity以及更加古老的jsp,左右后台渲染前台页面的控制器;
AOP则是对面向切面编程思想的支持,他给我们提供了面向切面编程的接口;
MySQL则是非常主流的数据库驱动;
Mybatis则为我们在数据库与函数之间建立了一个DAO(Data Access Object)层,方便我们不用写jdbc的代码就能访问数据;
Redis则是非常流行的NOSQL数据库,适合对一些数据做缓存处理以及快速的读取写入;
DevTools则提供了很多方便我们编程的特性,让IDE反应更快。。。
事实上这个网站做的事情也很简单,就是构建了下面的文件结构:
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ └── DemoApplication.java
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── java
└── com
└── example
└── demo
└── DemoApplicationTests.java
说白了其实就是配置了maven的包管理系统,以及推荐的文件结构,仅此而已。
什么是maven
maven其实就是一个包管理工具,就像是python的pip,ubuntu的apt,js的npm,在www.maven.org里集成了绝大多数大家常用的包信息,类似于webservice的注册中心。maven将本项目所有的包依赖全都写进了pom.xml文件中,免得我们一个一个下载再一个一个放进build path里,免去了很多的麻烦。
上面的配置形成的pom.xml如下:
1 | <?xml version="1.0" encoding="UTF-8"?> |
如果我们想重新加入一个包,只要在maven的管理中心找到这个包的groupId以及artifactId然后写在这里的dependency里就行了。最后利用IDE提供的自动导入maven包即可。
配置文件
相比于曾经写项目每个组件都有一个xml配置文件,SpringBoot都帮我们封装成了一个统一的配置文件application.properties,比如在某一个项目中我的配置是这样的:
1 | #tomcat start |
这其实就是对传统的配置方法做了一层封装,使得项目更加简洁清楚,所有的配置项也都能由IDE自动补全,不要太爽。
最后
由于这个框架比较新,因此很多组建都需要java8的支持,并且如果以后发布到服务器上,也需要Tomcat8的支持,这一点需要尤其的注意。
「Java教程」多线程
多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
程序的执行其实都是在抢 CPU 的资源,CPU 的执行权。
多个进程是在抢这个资源,而其中的某一个进程如果执行路径(线程)比较多,就会有更高的几率抢到 CPU 的执行权。
Web 性能优化(4)——localstorage 存储静态文件的意义
localstorage 并不仅仅只是”狂拽酷炫吊炸天“的黑科技。在一些特殊场景下,甚至可能会有意想不到的收获。
NPM 学习笔记整理
「Java教程」IO机制
输入输出(I/O)是指程序与外部设备或其他计算机进行交互的操作。几乎所有的程序都具有输入与输出操作,Java把这些输入与输出操作用流来实现,通过统一的接口来表示,从而使程序设计更为简单。
C++11学习笔记3
右值引用
分类
在古老的标准里,C++中的变量分为左值(lvalue)与右值(rvalue)这两种,左值就是能够用&获得地址的值,可以对他进行修改,右值就是不能用&获得地址的值,通常只是临时变量,不能进行修改。而在C++11中,变量不再仅仅分为左值与右值了,他引入了另一种值叫将亡值(expire value,xvalue)。从此,变量类型分为了三种:
- lvalue :left value 就是传统意义上的左值
- xvalue :expire value 就是将亡值
- prvalue :pure right value 就是传统意义上的右值
而且,xvalue+prvalue又称为rvalue,lvalue+xvalue又称为glvalue。
定义
那么什么是xvalue呢,什么又是右值引用呢?
xvalue其实就是对右值的引用:
1 | int &&x=10; |
这个x跟传统的左值引用肯定是不一样的,毕竟左值引用是不能引用右值的。
这个x跟左值变量也是不一样的,虽然看上去没啥区别,但是实际上这个x并没有进行构造,而是像左值引用一样,对右值10进行了引用,使得这个右值的内存不被立即释放。这样我们就可以像使用左值一样的使用这个右值了。
那么现在就应该清楚了,右值引用就是通过对右值进行引用使得我们能够保存这个右值的生命周期,并像使用左值一样的使用右值的方法。(自己的定义)
用途
这么费劲心机定义一个右值引用有啥意义呢?其实主要是为了提高变量传递的效率。虽然很多情况下,我们的编译器会做一些优化,但是不同编译器不同,因此下面基于g++的测试我开启了-fno-elide-constructors
参数防止其优化。
比如下面的这个过程:
1 | #include<iostream> |
看上去没什么额外开销,而事实上,这个过程的执行结果是:
1 | construct |
也就是说他执行了一次构造,一次拷贝构造。而事实上,这个拷贝构造是浪费额外开销的,而且这个拷贝其实是对一个右值的拷贝,在拷贝后这个右值就被析构了,我们完全可以不执行析构而让新的值就用这个右值的引用。
旧的做法是使用常量引用来做这件事:
1 | int main(){ |
这避免了额外的拷贝,但是后果是这个值只能是常量,无法被修改。
如果使用了右值引用,那么这个问题就简单多了:
1 | int main(){ |
结果:
1 | construct |
这个右值引用既没有对结果进行拷贝,也能够让我们像使用一个左值一样的使用他。
移动拷贝构造
为什么引入移动拷贝构造,这是因为我们考虑到了以下问题:
我们知道,构造函数分为深拷贝和浅拷贝,默认的是浅拷贝,浅拷贝导致的结果就是拷贝出来的对象跟拷贝前的对象拥有相同的堆内元素,如果我们析构了拷贝前的对象,那么拷贝后的对象就无法使用了,因此浅拷贝不适合做赋值的移动操作;而深拷贝呢,又太浪费空间了,完全没有必要生成一个一模一样的对象然后把原先的再删除。因此就引入了拷贝构造这个东西。
比如下面的例子:
1 | class Test{ |
结果:
1 | construct |
移动构造的参数就是一个右值引用,他做的事是将移动源的所有堆内元素指针断开,并连上移动目的地的指针。这样移动源就可以安心的析构而不影响移动目的地的堆内元素。同时也省去了不必要的拷贝开销,效率非常的高。
std::move
移动构造有一个问题,就是他的参数必须是右值,这就带来一个问题,如果上面的main函数变成这样:
1 | int main(){ |
结果:
1 | construct |
由于t1是个左值,那么他会去执行拷贝构造而不会执行移动构造,这显然不是我们像看到的。
为了使左值的移动能够使用移动构造,我们就有了std::move这个东西,他的作用很简单,就是把左值变成右值引用。
1 | int main(){ |
结果:
1 | construct |
如我所愿。
注意一点就是在使用std::move()之后的对象t1这时候的堆内元素就已经无效了。
std::move()这么好用,显然c++中的模板都支持这个move语义。
std::emplace_back
我们知道了对象的构造,拷贝、移动都是要付出一些代价的,那我们很容易就会想到,当我们使用容器的时候,如果使用拷贝构造,显然效率很低;如果使用移动构造,那么还是会有一些移动的开销,需要执行移动构造函数,能不能有一种方法,直接在容器里执行构造函数,这样就既不用拷贝,也不用移动了呢?答案是当然有,这就是std::emplace_back方法。我们可以比较下面的三种方法:
拷贝插入
1 | int main(){ |
输出:
1 | construct |
移动插入
1 | int main(){ |
输出:
1 | construct |
emplace_back
1 | int main(){ |
输出:
1 | construct |
显然,这个emplace_back的效率是最高的。
参考资料
随时随地 Hexo——我是如何使用 Hexo 的
Hexo 是一个使用 Node.js 作为构建引擎的极速、简单且强大的静态博客架构。但 Hexo 只有在安装了 Hexo 的环境上才能运行。于是我设计了一套实现 Hexo 随时随地部署、随时随地发布的方案。