用spring mvc框架的模拟实现来学习反射和注解
来源:互联网 发布:tensorflow 人脸检测 编辑:程序博客网 时间:2024/04/27 08:35
1、springmvc架构
2、相应注解详解
2.1、Controller注解 Controlle类上面的注解
2.2、Service注解 业务层对象上面的注解
2.33、Qualitify注解 在controller层里面,扫面含有此注解的字段,然后根据字段注入Service bean对象
2.44、HandlerMapping注解 处理方法上面的注解
3、编写流程(这里我们主要写框架的核心部分,所以不能做到像springmvc那样详尽):
1、先定义上面四个注解
2、全包扫描(在init()方法里面完成)
3、将扫描到含有Controller和service注解的类保存到一个map集合(classMap),key为当前注解的value值,value为当前类的实例对象。
4、将扫描到的Qualitify注解的字段,注入相应的值,值为classMap.get(key),其中key的值是扫描到Qualitify的value值。因为此key就是对应service注解的实例对象。
5、最后将要扫描Controller注解,然后在扫描handlerMapping注解,这一步为了构建请求地址,并且通过请求地址可以找到对应的方法的method对象和Controller注解对应类的实例对象。
首先,找到controller对象,通过集合(classmap)调用get(controller注解的value)方法得到对应的Controller类的实例对象,接下来扫描的是方法上面的注解,如果方法上面有HandlerMapping注解,然后构建ServletContext(项目名称,例如/上下文路径/资源具体路径)后面的url,如何构建呢?即Controller注解的value值加上HandllerMapping注解的value值,然后,在将此url作为key,然后扫描到的方法的Method对象作为value保存到一个Map(methodMap)集合,并且将此url作为key,controller注解对应的实例对象作为value,保存在classMap集合中。
6、此时就可以通过请求的url后面的路径映射到一个相应的method对象并且得到相应的controller类的实例。
代码部分:
包结构:
代码:
/** * Controller注解 * * */@Target({ElementType.TYPE})//作用在类上@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Controller { String value() default "";}
/** * Quatifier注解 * * */@Target({ElementType.FIELD})//作用在字段上@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Quatifier { String value() default "";}
/** * RequestMapping注解 * * */@Target({ElementType.METHOD})//作用在方法上@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestMapping { String value() default "";}
/** * Servic注解 * * */@Target({ElementType.TYPE})//作用在类上@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Service { String value() default "";}
@Controller("SpringMvcController")public class SpringMvcController { /** * 把UserService实例对象注入进来 * */ @Quatifier("UserServiceImpl") private UserService us; @RequestMapping("insert.action") public String insert(HttpServletRequest request, HttpServletResponse response, String param) { us.insert(null); try { request.getRequestDispatcher("/index.jsp").forward(request, response); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ServletException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @RequestMapping("delete.action") public String delete(HttpServletRequest request, HttpServletResponse response, String param) { us.delete(null); return null; } @RequestMapping("update.action") public String update(HttpServletRequest request, HttpServletResponse response, String param) { us.update(null); return null; } @RequestMapping("select.action") public String select(HttpServletRequest request, HttpServletResponse response, String param) { us.select(null); return null; } }
public interface UserService { int insert(Map map); int delete(Map map); int update(Map map); int select(Map map); }
@Service("UserServiceImpl")public class UserServiceImpl implements UserService{ @Override public int insert(Map map) { System.out.println("调用了插入方法"); return 0; } @Override public int delete(Map map) { System.out.println("调用了删除方法"); return 0; } @Override public int update(Map map) { System.out.println("调用了更新方法"); return 0; } @Override public int select(Map map) { System.out.println("调用了查询方法"); return 0; }}
核心控制器,只需在web.xml文件中配置它就可以了。
public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1L; //保存扫描到的所有包名 List<String> packageNames = new ArrayList<String>(); //所有类的实例,key是注解的value,value是注解对应的类的实例对象 Map<String, Object> instanceMap = new HashMap<String, Object>(); /** * 处理器映射到的方法对象集合 * key是地址栏上项目上下文后面接上的地址 * value是对应的方法对象也就是Method对象 * */ Map<String, Object> handerMap = new HashMap<String, Object>(); @Override public void init() throws ServletException { //扫描包中的文件 scanPackage("com.bjsxt.springmvc"); try { //将注解和对应的实例对象保存在集合当中 filterAndInstance(); } catch (Exception e) { e.printStackTrace(); } //建立映射关系 handderMap(); //依赖注入 ioc(); } //建立映射关系 private void handderMap() { if (instanceMap.size() <= 0) { return; } for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { //判断类上是否有Controller注解,在做下一步操作 if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) { Controller controller = (Controller)entry.getValue().getClass().getAnnotation(Controller.class); String cvalue = controller.value(); //拿到controller注解对应的对象 Object ctlObj = instanceMap.get(cvalue); Method[] methods = entry.getValue().getClass().getMethods(); for (Method method : methods) { //迭代方法,判断方法上面是否有requestMapping注解 if (method.isAnnotationPresent(RequestMapping.class)) { String value = ((RequestMapping)method.getAnnotation(RequestMapping.class)).value(); String urlKey = "/"+cvalue+"/"+value; //将地址和方法对象建立关系 handerMap.put(urlKey, method); //将地址和对象也建立映射关系。 instanceMap.put(urlKey, ctlObj); }else{ continue; } } } } } //属性的注入 private void ioc() { //如果集合为空,直接跳出此方法的执行 if (instanceMap.isEmpty()) { return; } for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { Field[] fields = entry.getValue().getClass().getDeclaredFields(); //迭代所有注解 for (Field field : fields) { field.setAccessible(true); //判断字段上面是否有Quatifier注解 if (field.isAnnotationPresent(Quatifier.class)) { //拿到注解 Quatifier quatifier = field.getAnnotation(Quatifier.class); //拿到注解对应的value值 String value = quatifier.value(); try { //注入相应的值 field.set(entry.getValue(),instanceMap.get(value)); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } /** * 扫描包下的所有文件 * */ private void scanPackage(String packagePath) { String loc = "/"+replaceTo(packagePath); System.out.println("扫描的地址:"+loc); URL url = this.getClass().getClassLoader().getResource(loc); System.out.println("url"+url); String filePath = url.getFile(); File f = new File(filePath); String[] fileList = f.list(); //迭代fileList for (String path : fileList) { File eachFile = new File(filePath+"/"+path); //判断是否是一个目录 if (eachFile.isDirectory()) { //到这里说明他是一个目录,我们还需要对子目录进行扫描 scanPackage(packagePath+"."+eachFile.getName()); }else{ //获得加后缀名的完整包名 String packName = packagePath+"."+eachFile.getName(); //去除文件后缀名,可得到包名+类名 String pName = packName.substring(0, packName.lastIndexOf(".class")); packageNames.add(pName); System.out.println("所有的包名加类名:"+packageNames); } } } //扫描 private void filterAndInstance()throws Exception { if (packageNames.size() <=0) { return; } for (String className : packageNames) { //加载实例 Class<?> cName = Class.forName(className.replace(".class", "").trim()); //判断是否有Controller注解 if (cName.isAnnotationPresent(Controller.class)) { Object instance = cName.newInstance(); //获得注解对象 Controller controller = (Controller) cName.getAnnotation(Controller.class); String key = controller.value(); //把注解的value的值作为key,对应的实例对象作为value instanceMap.put(key, instance); //判断是否有Service注解 }else if(cName.isAnnotationPresent(Service.class)){ Object instance = cName.newInstance(); Service service = (Service)cName.getAnnotation(Service.class); String key = service.value(); instanceMap.put(key, instance); } else{ continue; } } } //将所有的 . 转换成 / private String replaceTo(String packagePath) { return packagePath.replaceAll("\\.", "/"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获得请求的全路径 String url = req.getRequestURI(); System.out.println("uri的路径"+url); //获得上下文路径,通常是项目名 String context = req.getContextPath(); //去掉上下文 String path = url.replace(context, ""); System.out.println(path); Method m = (Method) handerMap.get(path); System.out.println(m); //打印地址栏上去掉contextPath之后的url System.out.println(path); try { //获得路径对应到的controller对象 Object obj = instanceMap.get(path); System.out.println(obj); //通过反射调用方法 m.invoke(obj, req,resp,null); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
web.xml
<servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>com.bjsxt.springmvc.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
- 用spring mvc框架的模拟实现来学习反射和注解
- 使用JAVA注解和反射模拟spring的IOC
- Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)
- 以SpringIoc的模拟实现来学习反射和xml解析
- 关于spring mvc,spring data,spring,MongoDB整合框架的一些思考和常用注解
- Spring框架注解的学习
- Spring MVC 学习笔记(二) 基于spring2.5注解实现的spring MVC项目
- Spring MVC 学习笔记(二) 基于spring2.5注解实现的spring MVC项目
- Spring 利用springIOC和DI实现MVC的模拟例子
- spring mvc注解实现
- spring mvc注解实现
- spring mvc注解实现
- spring mvc注解实现
- spring mvc框架源码分析(二)-自定义注解以及通过反射获取注解
- Spring MVC学习---JSON转换功能(启动Spring MVC的注解功能,完成请求和注解POJO的映射)
- spring MVC注解模式的经典实现
- Spring框架学习【解析和注入注解配置的资源】
- Spring mvc基于注解的学习
- Vim光标定位操作快捷键
- 实验吧_隐写_小苹果
- 动态规划-最长公共子序列、最长公共子串
- 晨间日记 自用
- 集合collection 接口
- 用spring mvc框架的模拟实现来学习反射和注解
- JSTL表达式标签
- 算法设计周记(五)--字典排序
- emp的反射案例
- C语言之指针专题一:指针变量和指针所指向的内存空间是两个不同的概念
- HTTP网页错误代码解释
- 浅谈git与github
- 如何阻止表单的默认提交事件
- Fragment的返回键 处理