springmvc之定制简易注解框架
一.前言
定制化手写注解实现SpringMVC底层原理。虽然代码简单,但是五脏俱全,实现了springmvc原理的整个过程。先了解下springmvc的原理流程图:
二.实现流程
项目工程目录
poml文件添加
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
增加web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.sxkj.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value> config/application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
1.定义注解
1.CustomController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomController {
String value() default "";
}
2.CustomService
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomService {
String value() default "";
}
3.CustomRequstMapping
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequstMapping {
//表示访问该方法的url
String value() default "";
}
4.CustomAutowired
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomAutowired {
String value() default "";
}
5.CustomRequstParam
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequstParam {
//表示参数的别名,必填
String value() ;
}
2.添加controller层方法UserController
@CustomController
@CustomRequstMapping("/test")
public class UserController {
@CustomAutowired(value = "UserServiceImpl")
UserServiceInter userServiceInter;
@CustomRequstMapping("/getName")
public void getUserName(HttpServletResponse response,@CustomRequstParam("id") String id) throws IOException {
String userName = userServiceInter.getUserName(id);
PrintWriter writer = response.getWriter();
writer.write(userName);
}
}
3.添加service层方法
UserServiceInter
public interface UserServiceInter {
String getUserName(String id);
}
UserServiceImpl
@CustomService(value = "UserServiceImpl")
public class UserServiceImpl implements UserServiceInter {
@Override
public String getUserName(String id) {
System.out.println("用户Id:"+id);
return "hello,id:"+id;
}
}
4.添加servlet,DispatcherServlet(主要实现)
public class DispatcherServlet extends HttpServlet {
//存放扫描包下的所有文件集合
private List<String> mClassNames=new ArrayList<String>();
//存放实例化对象的集合容器 Customcontroller,Customservice注解的对象
private Map<String,Object> mBeans=new HashMap<String, Object>();
//存放url映射的路径信息
private HashMap<String,Object> mHandleUrlMapping=new HashMap<String, Object>();
@Override
public void init() throws ServletException {
super.init();
System.out.println("初始化");
initScanFile("com.sxkj");//扫描所有的包下目录的所有文件
initInstance();//初始化实例化对象
initAutowired();//实例化autowired注解对象到该类的controller字段对象
initHandleUrlMapping();//处理url映射关系
}
/**
* @Description 处理url映射关系
**/
private void initHandleUrlMapping() {
for (Map.Entry<String,Object> entry:mBeans.entrySet()) {
//遍历集合容器中的对象
Object instance = entry.getValue();
//根据实例化对象拿到类的对象
Class<?> clazz = instance.getClass();
//判断是否为控制类
if (clazz.isAnnotationPresent(CustomController.class)) {
//拿到customRequstMapping注解对象
CustomRequstMapping customRequstMapping=clazz.getAnnotation(CustomRequstMapping.class);
//拿到controller上改注解的值 如:/test
String classPath = customRequstMapping.value();
//拿到该类的所有方法
Method[] methods = clazz.getMethods();
for (Method method:methods){
//判断该方法是否有customRequstMapping注解
if(method.isAnnotationPresent(CustomRequstMapping.class)){
//拿到customRequstMapping注解对象
CustomRequstMapping requstMapping=method.getAnnotation(CustomRequstMapping.class);
//拿到该值 如:/getName
String methodPath = requstMapping.value();
//将路径 /test/getName 放入map容器中
mHandleUrlMapping.put(classPath+methodPath,method);
}else {
continue;
}
}
}else {
continue;
}
}
}
/**
* @Description 初始实例化autowired注解的对象
**/
private void initAutowired() {
for (Map.Entry<String,Object> entry:mBeans.entrySet()){
//遍历集合容器中的对象
Object instance = entry.getValue();
//根据实例化对象拿到类的对象
Class<?> clazz=instance.getClass();
if(clazz.isAnnotationPresent(CustomController.class)){
//获取该类的成员变量
Field[] fields = clazz.getDeclaredFields();
//遍历成员变量
for (Field field:fields){
//判断该变量是否有customAutored注解
if(field.isAnnotationPresent(CustomAutowired.class)){
CustomAutowired customAutowired=field.getAnnotation(CustomAutowired.class);
//获取该注解的value值,该值为mBean的key值
String key = customAutowired.value();
//通过该key值获取对象
Object value=mBeans.get(key);
//让该字段获取权限,让其可访问私有变量
field.setAccessible(true);
try {
//将该service类对象设置到controller类中的autowwired字段值去
field.set(instance,value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}else {
continue;
}
}
}else {
continue;
}
}
}
/**
* @Description 实例化对象(扫描过的文件且有注解的)
**/
private void initInstance() {
for (String className:mClassNames){
//如: com.sxkj.annotation.CustomAutowire.class 将.class后缀去掉
String name = className.replace(".class", "");
try {
//通过文件名拿到类
Class<?> clazz = Class.forName(name);
//判断该类是否有CustomController注解类
if(clazz.isAnnotationPresent(CustomController.class)){
//实例化对象
Object instance = clazz.newInstance();
//获取该类上的注解的requstmapping中的value值
CustomRequstMapping customRequstMapping=clazz.getAnnotation(CustomRequstMapping.class);
mBeans.put(customRequstMapping.value(),instance);
} else if (clazz.isAnnotationPresent(CustomService.class)) {
//实例化对象
Object instance = clazz.newInstance();
//获取该类上的注解的requstmapping中的value值
CustomService customService=clazz.getAnnotation(CustomService.class);
mBeans.put(customService.value(),instance);
}else {
continue;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* @Description 扫描文件
**/
private void initScanFile(String basepackage) {
URL url = this.getClass().getClassLoader().getResource("/" + basepackage.replaceAll("\\.", "/"));
String files = url.getFile();
File file = new File(files);
String[] fileList = file.list();
for (String filePath:fileList){
File filePaths = new File(files + filePath);
if(filePaths.isDirectory()){
initScanFile(basepackage+"."+filePath);
}else {
// com.sxkj.annotation.CustomAutowire.class
mClassNames.add(basepackage+"."+filePaths.getName());
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest requset, HttpServletResponse response) throws ServletException, IOException {
//获取请求的路径
String requestURI = requset.getRequestURI();//获取到工程名+请求路径
//将工程名去掉,最后为请求路径 /test/getName
String contextPath = requset.getContextPath();
//切割后最后为请求的路径 /test/getName
String urlPath=requestURI.replace(contextPath,"");
//通过路径获取到mHandleUrlMapping容器中的值 method
Method method= (Method) mHandleUrlMapping.get(urlPath);
//通过路径 /test 获取到CustomController的实例化对象
Object instance = mBeans.get("/" + urlPath.split("/")[1]);
Object[] args = handleArgs(requset, response, method);
//执行方法
try {
method.invoke(instance,args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private static Object[] handleArgs(HttpServletRequest request,HttpServletResponse response,Method method){
//获取当前执行的方法有哪些参数
Class<?>[] parameterTypes = method.getParameterTypes();
//根据参数的个数,new出数组参数的数量,将方法的所有参数复制到arg[]里面来
Object[] args = new Object[parameterTypes.length];
int arg_i=0;int index=0;
for (Class<?> paramClass:parameterTypes){
if(ServletRequest.class.isAssignableFrom(paramClass)){
args[arg_i++]=request;
}if(ServletResponse.class.isAssignableFrom(paramClass)){
args[arg_i++]=response;
}
Annotation[] annotations = method.getParameterAnnotations()[index];
if(annotations.length>0){
for (Annotation annotation:annotations){
if(CustomRequstParam.class.isAssignableFrom(annotation.getClass())){
CustomRequstParam customRequstParam= (CustomRequstParam) annotation;
//获取注解里面的参数
args[arg_i++]=request.getParameter(customRequstParam.value());
}
}
}
index++;
}
return args;
}
}
5.测试
访问 http://localhost:8081/test/getName?id=12 ,结果:
hello,id:12