Mvc框架开发
问题背景:
代码和项目工程已上传到我的资源下载...需要的可以下载
在每次我们开发一些小的web应用时(个人博客,公司门户网站,公司展示性网站,小型企业形象网站),我们通常要么采用jsp + servlet开发,要么采用spring mvc,或者strut 2框架进行开发。在使用jsp + servlet开发的时候,我们面临的最大缺点就是:
缺点1:servlet过多,以及每个servlet的入口通常情况下只有两个doGet() or doPost()。所以在每个servlet中,我们又不得不加入一些标志符进行判断。比如:一个关于学生操作的servlet,让我们叫它为StudentServlet。在这个servlet中,我们可能要对学生完成的操作:login(登陆),delete(删除),update(更新),find(查找)。为了减少servlet的个数,我们通常将类似的操作归类,所以上面的方法都是有关学生的操作,我将它们都放在StudentServlet中。为了区分每次请求的操作,我们可能会使用一个标识符,我们称它为 operateFlag。所以这给我们的开发带来了很多重复的工作。比如一个公司门户网站,可能相同的servlet有几十个...每次都进行这样子的开发,你是否觉得很乏味呢?
缺点2:每个servlet,在WEB-INF下面的web.xml中,我们都要进行类似如下的配置
<servlet>
<servlet-name>StudentServlet</servlet-name>
<servlet-class>net.itaem.servlet.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StudentServlet</servlet-name>
<url-mapping>/student.do</url-mapping>
</servlet-mapping>
所以这样子会导致web.xml内容庞大,稍不注意,出现问题了,就需要花很多时间进行修改。
缺点3:
每次发送请求时,很可能就是有关于一个表单的操作。比如学生注册,那么这个学生的注册信息假设包括:学号,姓名,年龄,性别,生日,电话,邮箱,家庭地址,户口...等这些信息。如果在使用servlet开发时,我们就不得不在后台写类似下面的代码:
Student student = new Student();
String name = request.getParameter(“name”);
String age = request.getParameter(“age”);
...
并且还可能需要将字符串的年龄转换为数字...虽然这些开发步骤简单,但是当相同代码非常多的时候,就会让人厌烦...并且对自己的开发经验的积累,起到的作用甚微(当然,这里不包括初学者,初学者建议反复使用jsp + servlet开发)。
下面给出金典的mvc结构图:
下面给出简略的图形,对进一步的mvc设计将会带来帮助,下面的图假设user为网站的使用用户,后台处理程序为对应的处理用户请求的servlet...其它的service层,dao层等省略
对于小的项目开发,以上三个问题是最明显的。当然,根据开发的经验不同,每个人的理解也会有一些不同,以上观点,纯属个人见解,如果错误或者不到位的,大家可以指出...
为了解决上诉的几个问题,下面我主要描述解决方案,具体代码,还在进一步开发中。
问题1的解决方案:采用类似于spring mvc的方式,用注解来实现。比如在所有的servlet中,加入自己开发的注解,然后在程序启动时,加载核心servlet,然后这个核心servlet把所有的相关的servlet类,加载到程序中。
问题2的解决方式:每个自定义的servlet(也就是使用了注解的servlet类),在每个业务逻辑方法中,加入相应的注解,达到请求与处理的servlet以及方法的自动适配。这样子可以解放servlet,而不是仅仅局限于在doGet(), doPost()方法中。这个解决方案的解决方式主要借助spring mvc的注解,以及注入思想。
问题3的解决方式:自己写个反射的方法,将请求中所有的参数取出来,然后封装成一个请求所需要的对象。比如注册学生,可以把注册信息都取出来,然后封装成一个Student,直接传给相关servlet的相关方法,这样子使用起来就更加方便。所以这里要求:每个请求对象都是标准的java bean对象。
下面给出解决方案的关键思想的图片:类似于在请求之前,先进行一遍过滤,然后把信息整理好之后,在下发到一个具体的处理servlet中,是后面的开发更加快捷。所以在这里可以加入字符串转码...或者提供接口,让用户自行选择编码格式。
总结:
虽然一些门户网站开发,我们完全可以使用spring mvc, struts等成熟框架。但是从目前开发的经验来看,虽然这些框架可以提高开发速度,但是这些框架对于我们团队目前而言还是过大了。导致一个小小的项目,也会因为加载的jar包过多,然后出现臃肿的情况。并且框架开发,在运行速度上是稍微比较慢的,因为框架开发是针对整个java web开发的,里面拥有的类数目也是非常多的。所以我们需要花时间学习这些框架,搭建开发环境...但是收获的内容并不是特别多。所以个人决定,找个时间我们自己开发一个小的框架,以后我们自己开发一些小东西的时候,就直接采用自己的框架便可满足我们的需要...
下面是工程的主要类
注解类:
ServletAnnotation,ProcessMethodAnnotation
工具类:
ClassUtil
核心类
CoreServlet
主要的框架图片
类的结构图:
可以直接参考工程的源代码...放在net.itaem.mvc包下面
下面给出具体的源代码:
package net.itaem.mvc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 用来注解相关的类,使用了该类注解的类充当Servlet
*
* @author 骆宏
* @QQ 846705189
* */
@Retention(value=RetentionPolicy.RUNTIME)
@Target(value=ElementType.TYPE)
public @interface ServletAnnotation {
/**
* 该类的key值
* */
String servletMappingValue();
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
package net.itaem.mvc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 这个类用来注解要进行处理的方法
* 其中methodMappingValue作为方法的key
* @author 骆宏
* @QQ 846705189
* */
@Target(value=ElementType.METHOD)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface ProcessMethodAnnotation {
/**
* 处理方法的key值
* */
String methodMappingValue();
}
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> </span>
package net.itaem.mvc;
/**
* 这个异常是运行时异常
* 作用:在初始化CoreServlet的时候,会加载配置文件
* 在加载配置文件中,如果两个使用了ServletAnnotation注解类的值相同或者
* 使用了ProcessMethodAnnotation注解方法的值相同
* 就会报错。防止Servlet映射相同,防止出现一个Sevlet中有多个相应的处理方法存在
*
* @author luohong
* @time 2014-04-12
* */
@SuppressWarnings("serial")
public class IteamInitializationException extends RuntimeException {
public IteamInitializationException(String message){
super(message);
}
}
package net.itaem.mvc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 这个类用来注解要进行处理的方法
* 其中methodMappingValue作为方法的key
* @author 骆宏
* @QQ 846705189
* */
@Target(value=ElementType.METHOD)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface ProcessMethodAnnotation {
/**
* 处理方法的key值
* */
String methodMappingValue();
}
package net.itaem.mvc;
/**
* 这个异常是运行时异常
* 作用:在初始化CoreServlet的时候,会加载配置文件
* 在加载配置文件中,如果两个使用了ServletAnnotation注解类的值相同或者
* 使用了ProcessMethodAnnotation注解方法的值相同
* 就会报错。防止Servlet映射相同,防止出现一个Sevlet中有多个相应的处理方法存在
*
* @author luohong
* @time 2014-04-12
* */
@SuppressWarnings("serial")
public class IteamInitializationException extends RuntimeException {
public IteamInitializationException(String message){
super(message);
}
}
package net.itaem.mvc;
import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* 使用该类来获取指定包下面的所有类
* 这里面主要有两个方法,一个是递归获取某个包下面所有的类
* 另外一个是根据Annotation来获取指定的类文件
* */
class ClassUtil {
public static void main(String[] args) {
System.out.println(getClassList("net.itaem.servlet", false));
System.out.println("--------------------------------");
System.out.println(getClassListByAnnotation("net.itaem.servlet", ServletAnnotation.class));
}
/**
* @param packageName 要获取类的包名
* @param isRecursive 是否要递归
* @return 找到指定包下面的类,然后返回一个类的集合
* */
public static List<Class<?>> getClassList(String packageName, boolean isRecursive){
List<Class<?>> classList = new ArrayList<Class<?>>();
try{
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\.", "/"));
while(urls.hasMoreElements()){
//找到文件的绝对位置
URL url = urls.nextElement();
if(url != null){
//获取协议内容
String protocol = url.getProtocol();
//文件协议
if(protocol.equals("file")){
//找到绝对路径
String packagePath = url.getPath();
//将这个类添加到
addClass(classList, packagePath, packageName, isRecursive);
//jar文件协议
}else if(protocol.equals("jar")){
JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
String jarEntryName = jarEntry.getName();
if(jarEntryName.endsWith(".class")){
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
if(isRecursive || className.subSequence(0, className.lastIndexOf(".")).equals(packageName)){
classList.add(Class.forName(className));
}
}
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
return classList;
}
/**
* @param packageName 要获取类的包名
* @param isRecursive 是否要递归
* @return 找到指定包下面的类并且指定Annotation来过滤,然后返回一个类的集合
* */
public static List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass){
List<Class<?>> classList = new ArrayList<Class<?>>();
try{
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\.", "/"));
while(urls.hasMoreElements()){
URL url = urls.nextElement();
//为了防止url出现一些特殊符号,导致程序不能识别,所以这里讲url进行解码
url = new URL(URLDecoder.decode(url.toString(), "utf-8"));
if(url != null){
String protocol = url.getProtocol();
if(protocol.equals("file")){
String packagePath = url.getPath();
addClassByAnnotation(classList, packagePath, packageName, annotationClass);
}else if(protocol.equals("jar")){
JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
String jarEntryName = jarEntry.getName();
if(jarEntryName.endsWith(".class")){
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
Class<?> cls = Class.forName(className);
if(cls.isAnnotationPresent(annotationClass)){
classList.add(cls);
}
}
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
return classList;
}
private static void addClassByAnnotation(List<Class<?>> classList, String packagePath, String packageName, Class<? extends Annotation> annotationClass){
try{
File[] files = getClassFiles(packagePath);
if(files != null){
for(File file: files){
String fileName = file.getName();
if(file.isFile()){
String className = getClassName(packageName, fileName);
Class<?> cls = Class.forName(className);
if(cls.isAnnotationPresent(annotationClass)){
classList.add(cls);
}else{
String subPackagePath = getSubPackagePath(packagePath, fileName);
String subPackageName = getSubPackageName(packageName, fileName);
addClassByAnnotation(classList, subPackagePath, subPackageName, annotationClass);
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
private static void addClass(List<Class<?>> classList, String packagePath, String packageName, boolean isRecursive){
try{
//找到所有的class文件
File[] files = getClassFiles(packagePath);
if(files != null){
//遍历每一个class文件
for(File file: files){
String fileName = file.getName();
if(file.isFile()){
//得到类的全路径名字
String className = getClassName(packageName, fileName);
//将类添加到集合中
classList.add(Class.forName(className));
}else{
//递归
if(isRecursive){
//子路径
String subPackagePath = getSubPackagePath(packagePath, fileName);
//子路径名
String subPackageName = getSubPackageName(packageName, fileName);
addClass(classList, subPackagePath, subPackageName, isRecursive);
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
private static String getSubPackagePath(String packagePath, String filePath){
String subPackagePath = filePath;
if(packagePath != null && !"".equals(packagePath)){
subPackagePath = packagePath + "/" + subPackagePath;
}
return subPackagePath;
}
private static String getSubPackageName(String packageName, String filePath){
String subPackageName = filePath;
if(packageName != null && !"".equals(packageName)){
subPackageName = packageName + "/" + subPackageName;
}
return subPackageName;
}
//获得全路径类名比如:net.itaem.servlet.StudentServet
private static String getClassName(String packageName, String fileName){
String className = fileName.substring(0, fileName.lastIndexOf("."));
if(packageName != null && !"".equals(packageName)){
className = packageName + "." + className;
}
return className;
}
private static File[] getClassFiles(String packagePath){
return new File(packagePath).listFiles(new FileFilter(){
public boolean accept(File file){
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
}
//获取某个类的所有属性名
public static List<String> getPeropertiesName(Class<?> clazz, List<String> fieldNameList){
//防止出现NullPointerException
if(clazz == null) return null;
//如果该类自己拥有属性,那么添加到集合中
if(clazz.getDeclaredFields().length > 0){
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields){
fieldNameList.add(field.getName());
}
}
//如果这个类继承了其它类,并且这个父类不是Object,那么递归遍历所有的父类,然后将父类的属性也查找出来
if(clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class){
//递归遍历所有的父类
return getPeropertiesName(clazz.getSuperclass(), fieldNameList);
}else{ //递归出口,这个类除了Object之外,没有其他父类了
return fieldNameList;
}
}
}
package net.itaem.mvc;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 每次请求,都需要经过这个CoreServlet,这个Servlet所要做的工作讲就是:封装请求数据,<br/>
* 匹配要进行业务逻辑的Servlet以及相应的方法<br/>
*
* 第一步:找到所有对应的Servlet,就是采用了@ServletAnnotation注解的类<br/>
* 第二步:将这些类保存在一个Map的集合中,key是注解的servletValue值,value是队形的Servlet类<br/>
* 第三步:将每个Servlet类中的处理方法也全部取出来,保存在Map中,第二部和第三部是相关联的<br/>
* <br/>
* 形成:一个ServletAnnotation注解值对应一个Servlet,一个Servlet中有多个方法,每个方法与ProcessMethodAnnotation注解值对应<br/><br/>
* 第四步:每次请求到来时,查找对应的Servlet,以及相应的方法<br/>
* 第五步:查看处理方法的参数,如果是自定义的类型,将request中的数据取出来,封装成自定义类型的对象<br/>
* 第五步:根据方法的返回值进行跳转
*
* 使用要求:a注解ServletAnnotation值不能重复,开头不要"/"<br/>
* b同一个类中ProcessAnnotation值不能重复,开头需要"/",并且结尾以".do"结尾<br/>
* c如果一个方法的的参数是原始数据类型,直接传入HttpServletRequest
* 或者HttpServletRepsonse(比如:删除学生,超链接中的参数只有学生id,所以这个方法直接传入HttpServletRequest即可)<br/>
* d方法返回值是相对根目录下下的某个jsp(可以包含.jsp也可以不包含)比如:"/success", "/success.jsp"<br/>
* c目前javabean对象必须是标准的javabean(具备setXxx(), getXxx()),并且现在处于开发中,所以只支持字符串类型,后期开发会修改这个bug
*
* @author 骆宏
* @QQ 846705189
* @date 2014-04-12
* */
public class CoreServlet extends HttpServlet {
/**
* 无意义
*/
private static final long serialVersionUID = 1L;
//定义一个保存所有servlet的map,key是使用ServletAnnotation设置的值,value是对应的相关Servlet对象
private static Map<String, Object> serMap = new HashMap<String, Object>();
//定义一个保存所有方法的map
private static Map<String, ArrayList<HashMap<String, Method>>> methMapListMap = new HashMap<String, ArrayList<HashMap<String, Method>>>();
private static String encoding = "";
//要加载的包
private static List<String> packageNameList = new ArrayList<String>();
@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 {
req.setCharacterEncoding(encoding);
resp.setCharacterEncoding(encoding);
process(req, resp);
}
@Override
public void init(ServletConfig config) throws ServletException {
encoding = config.getInitParameter("encoding");
String packageStrs = config.getInitParameter("packageName");
if(packageStrs != null){
String[] packageNames = packageStrs.split(" ");
for(String packageName: packageNames){
packageNameList.add(packageName);
}
}else{
throw new RuntimeException("包不能为空,请修改配置文件");
}
//加载配置文件之后,启动程序
setUp();
}
private void process(HttpServletRequest req, HttpServletResponse resp){
//第一步,解析请求的url
String url = req.getRequestURL().toString();
//取出工程名字
String context = req.getSession().getServletContext().getContextPath();
//取出请求的内容,包含servlet,以及相关方法的字符串,比如:/teacher/addTeacher.do
String reqUrl = url.substring(url.lastIndexOf(context)).replace(context, "");
//第二部,根据url去分发任务给不一样的Servlet
//第三部,找到相应的Servlet的相关处理方法
String servletName = reqUrl.substring(1, reqUrl.indexOf("/", 1));
String processMethodName = reqUrl.substring(reqUrl.indexOf("/", 1));
process(servletName, processMethodName, req,resp);
}
//调用这个相关servlet的相关方法
private void process(String servletName, String processMethodName, HttpServletRequest req, HttpServletResponse resp) {
//找到对应的Servlet
Object servlet = find(servletName);
//找到对应的Method
Method method = findMethod(servletName, processMethodName);
try {
Object object = null;
//但是如果是原始数据类型呢??
object = method.invoke(servlet, arguments(method, req, resp));
//有返回值,根据返回值做出jsp的跳转,或者是重定向;如果没有返回值,不做任何处理
if(object != null && object.getClass() != null && object.getClass().getSimpleName().equals("String")){
System.out.println("the return value is " + object);
try {
if(((String)object).contains(".jsp")){
req.getRequestDispatcher((String)object).forward(req, resp);
}else{
req.getRequestDispatcher((String)object + ".jsp").forward(req, resp);
}
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
System.out.println("the method return null");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//找到相关的Servlet
private synchronized Object find(String servletName){
Object servlet = serMap.get(servletName);
return servlet == null ? null : servlet;
}
//找到某个Servlet下面的某个方法
private synchronized Method findMethod(String servletName, String methodName){
//找到servlet下面的所有方法
ArrayList<HashMap<String, Method>> methMapList = methMapListMap.get(servletName);
Method method = null;
//找到具体的方法
for(HashMap<String, Method> methMap: methMapList){
if(methMap.containsKey(methodName)){
method = methMap.get(methodName);
break;
}
}
return method == null ? null : method;
}
//获得参数内容,封装成对象数组
private Object[] arguments(Method method, HttpServletRequest req, HttpServletResponse resp){
if(method == null) return null;
//将请求参数封装成对象
try {
Class<?>[] argTypes = method.getParameterTypes();
//将参数组装成一个数组
Object[] arguments = new Object[argTypes.length];
int index = 0;
for(Class<?> argType: argTypes){
//参数内容不能是原始数据类型以及不能是HttpServletRequest, HttpServletResponse
if(!isPrimitive(argType) && argType != HttpServletRequest.class && argType != HttpServletResponse.class){
try {
//取出里面的内容
arguments[index] = argType.newInstance();
reqToObject(arguments[index], req);
index++;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(argType == HttpServletRequest.class){
arguments[index] = req;
index++;
}else if(argType == HttpServletResponse.class){
arguments[index] = resp;
index++;
}
}
return arguments;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
//取出req中的请求对象属性,然后封装成T指定的对象
private <T> T reqToObject(T obj, HttpServletRequest req){
if(obj == null) return null;
//获得所有的属性
List<String> fieldNameList = ClassUtil.getPeropertiesName(obj.getClass(), new ArrayList<String>());
//遍历该对象的所有属性
for(String fieldName: fieldNameList){
//取出这个请求中属性的内容
String value = req.getParameter(fieldName);
//如果不为null,设置到该对象里面
if(value != null)
try {
//得到属性对应的setXxx()方法名字
String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//遍历这个对象里面的所有方法,然后找到对应的setXxx()方法,然后执行该方法
for(Method method: obj.getClass().getMethods()){
if(method.getName().equals(methodName)){
method.invoke(obj, value);
}
}
} catch (SecurityException e) {
e.printStackTrace();
}catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return obj;
}
//判断某个对象是否是原始数据类型
private boolean isPrimitive(Object obj){
if(obj.getClass().getSimpleName().equals("Character") || obj.getClass().getSimpleName().equals("Byte")
|| obj.getClass().getSimpleName().equals("Integer") || obj.getClass().getSimpleName().equals("Float")
|| obj.getClass().getSimpleName().equals("Long") || obj.getClass().getSimpleName().equals("Double")
|| obj.getClass().getSimpleName().equals("Void") || obj.getClass().getSimpleName().equals("Boolean")
|| obj.getClass().getSimpleName().equals("Short")){
return true;
}else{
return false;
}
}
//加载配置文件,将Servlet以及相关方法建立好key-->value的联系
private void setUp(){
if(serMap.size() == 0 && methMapListMap.size() == 0){
List<Class<?>> classList = new ArrayList<Class<?>>();
for(String packageName: packageNameList){
//取出每个包下面使用了ServletAnnotation注解的类
classList.addAll(ClassUtil.getClassListByAnnotation(packageName, ServletAnnotation.class));
}
//保存这个类里面所有的注解方法
ArrayList<HashMap<String, Method>> methMapList = new ArrayList<HashMap<String, Method>>();
//初始化所有的ServletAnnotation类
for(Class<?> clazz: classList){
String servletMappingKey = null;
//取出ServletAnnotation注解类
Annotation anno = clazz.getAnnotation(ServletAnnotation.class);
//取出ServletAnnotation注解类里面的所有方法
Method[] methods = anno.annotationType().getDeclaredMethods();
//遍历这个Annotation中的所有方法
for(Method method: methods){
//找到servletMappingValue这个方法
if(method.getName().equals("servletMappingValue")){
//取出这个方法的值,然后作为map的key保存到一个map集合中
try {
servletMappingKey = (String)method.invoke(anno, null);
//将类添加到Map集合中,然后添加这个类下面使用ProcessMethodAnnotation注解的方法
if(!serMap.containsKey(servletMappingKey)){
serMap.put(servletMappingKey, clazz.newInstance());
//取出这个ServletAnnotation注解类里面的所有方法,然后取出里面使用了ProcessMethodAnnotation注解的方法,然后将这个方法保存在一个Map中
Method[] proMethods = clazz.getMethods();
HashMap<String, Method> methMap = new HashMap<String, Method>();
//遍历每个方法
for(Method proMethod: proMethods){
//取出这个注解了ProcessMethodAnnotation的方法
Annotation proAnno = proMethod.getAnnotation(ProcessMethodAnnotation.class);
//如果存在这个ProcessMethodAnnotation
if(proAnno != null){
//取出这个ProcessMethodAnnotation里面的所有方法
Method[] proMethAnnoMeths = proAnno.getClass().getDeclaredMethods();
//遍历所有的方法
for(Method proMethAnnoMeth: proMethAnnoMeths){
if(proMethAnnoMeth.getName().equals("methodMappingValue")){
//取出里面的设置的值
try {
String methodMappingKey = (String)proMethAnnoMeth.invoke(proAnno, null);
if(!methMap.containsKey(methodMappingKey)){
//保存到methMap中
methMap.put(methodMappingKey, proMethod);
}else{
throw new IteamInitializationException("有两个或者多个方法使用了同样的注解值,请修改。注解值为:" + methodMappingKey);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
//添加到集合中
methMapList.add(methMap);
}
//建立索引: servletName -> servlet class
methMapListMap.put(servletMappingKey, methMapList);
}else{
throw new IteamInitializationException("有两个或者多个类使用了同样的注解值,请修改。注解值为:" + servletMappingKey);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
}
}
}
}