该项目是一个轻量级MVC框架,重点实现了IOC和AOP特性,适合需要学习这两方面知识的人。
这个项目是博主在git上找到并且自己做了修改和注释的。希望可以帮到大家,也促进我自己的学习。其中原git地址为:git地址:https://github.com/wacxt/light-framework。博主的git地址为:https://github.com/wenjieyatou/light-framework。
项目的整体架构是:
(1):依赖注入的实现:通过BeanHelper(位于Helper包中)获取所有Bean Map(是一个记录了类与对象的映射关系的Map<Class<?>,Object>结构),遍历这个映射关系,取出Bean类与Bean实例,通过反射获取类中的所有成员变量,然后遍历这些变量,判断是否带有Inject注解,有的话从Map中取出Bean实例,通过Field.set方法来修改当前成员变量的值
(2):Aop的实现:使用动态代理来实现具有局限性:(1)代理类必须实现一个接口(2)反射大量生成类文件可能导致方法区触发Full GC。于是采用Cglib来实现 因为一个类可以被多重代理,(安全验证,时间计算等),采用了代理链的思路
项目的整体流程:
(1)DispatcherServlet的init方法实例化ClassHelper.class,BeanHelper.class,AopHelper.class,IocHelper.class,ControllerHelper.class
关键代码:
package com.light.framework; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.light.framework.bean.Handler; import com.light.framework.bean.Param; import com.light.framework.bean.View; import com.light.framework.helper.BeanHelper; import com.light.framework.helper.ConfigHelper; import com.light.framework.helper.ControllerHelper; import com.light.framework.helper.RequestHelper; import com.light.framework.helper.ServletHelper; import com.light.framework.helper.UploadHelper; import com.light.framework.util.ArrayUtil; import com.light.framework.util.CodeUtil; import com.light.framework.util.JsonUtil; import com.light.framework.util.ReflectionUtil; import com.light.framework.util.StreamUtil; import com.light.framework.util.StringUtil; /** * 请求转发器 * @author wenjie * @since 1.0.0 */ @WebServlet(urlPatterns = "/*", loadOnStartup = 0) public class DispatcherServlet extends HttpServlet { @Override public void init(ServletConfig serveltConfig) throws ServletException { //初始化相关Helper类,实例化各种Bean,解析注解 HelperLoader.init(); //获取ServletContext 对象(用于注册Servlet) ServletContext servletContext = serveltConfig.getServletContext(); //注册处理JSP 的 Servlet ServletRegistration jspServlet = servletContext.getServletRegistration("jsp"); String appJspPath = ConfigHelper.getAppJspPath() + "*"; jspServlet.addMapping(appJspPath); //注册处理静态资源的默认Servlet ServletRegistration defaultServlet = servletContext.getServletRegistration("default"); defaultServlet.addMapping(ConfigHelper.getAppAssertPath() + "*"); //初始化文件上传助手 UploadHelper.init(servletContext); } public void dservice(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{ //获取请求方法与请求路径 String requestMethod = request.getMethod().toUpperCase(); String requestPath = request.getPathInfo(); //获取Action处理器 Handler handler = ControllerHelper.getHandler(requestMethod, requestPath); if(handler != null){ //获取Controller类及其Bean实例 Class<?> controllerClass = handler.getControllerClass(); Object controllerBean = BeanHelper.getBean(controllerClass); //System.out.println(controllerBean.getClass().getName()); //创建请求参数对象 Map<String, Object> paramMap = new HashMap<String,Object>(); Enumeration<String> paramNames = request.getParameterNames(); while(paramNames.hasMoreElements()){ String paramName = paramNames.nextElement(); String paramValue = request.getParameter(paramName); paramMap.put(paramName, paramValue); } String body = CodeUtil.decodeURL(StreamUtil.getString(request.getInputStream())); if(StringUtil.isNotEmpty(body)){ String []params = StringUtil.splitString(body, "&"); if(ArrayUtil.isNotEmpty(params)){ for(String param : params){ String[] array = StringUtil.splitString(param,"="); if(ArrayUtil.isNotEmpty(array) && array.length == 2){ String paramName = array[0]; String paramValue = array[1]; paramMap.put(paramName, paramValue); } } } } Param param = new Param(paramMap); //调用Action方法 Method actionMethod = handler.getActionMethod(); //System.out.println(actionMethod); Object result; // 这里需对 param 处理, if(paramMap != null && paramMap.size() > 0){ result = ReflectionUtil.invokedMethod(controllerBean, actionMethod, param); }else{ result = ReflectionUtil.invokedMethod(controllerBean, actionMethod); } //处理Action方法返回值 if(result instanceof View){ //返回JSP页面 View view = (View) result; String path = view.getPath(); if(StringUtil.isEmpty(path)){ if(path.startsWith("/")){ response.sendRedirect(request.getContextPath() + path); }else{ Map<String,Object> model = view.getModel(); for(Map.Entry<String, Object>entry : model.entrySet()){ request.setAttribute(entry.getKey(), entry.getValue()); } request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(request, response); } } else if(result instanceof Data){ //返回JSON数据 Data data = (Data)result; Object model = data.getModel(); if(model != null){ response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); String json = JsonUtil.toJson(model); writer.write(json); writer.flush(); writer.close(); } } } } } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletHelper.init(request, response); try{ //获取请求方法与请求路径 ,获取客户机的请求方式 String requestMethod = request.getMethod(); String requestPath = request.getPathInfo(); if(requestPath.equals("/favicon.ico")){ return; } //获取Action 处理器 Handler handler = ControllerHelper.getHandler(requestMethod, requestPath); if(handler != null){ //获取Controller类极其Bean实例 Class<?> controllerClass = handler.getControllerClass(); Object controllerBean = BeanHelper.getBean(controllerClass); Param param; if(UploadHelper.isMultipart(request)){ param = UploadHelper.createParam(request); }else{ param = RequestHelper.createParam(request); } Object result; Method actionMethod = handler.getActionMethod(); if(param.isEmpty()){ result = ReflectionUtil.invokedMethod(controllerBean, actionMethod); }else{ result = ReflectionUtil.invokedMethod(controllerBean, actionMethod, param); } if(result instanceof View){ handleViewResult((View)result, request, response); }else if( result instanceof Data){ handleDataResult((Data) result,response); } } }finally{ ServletHelper.destory(); } } private void handleViewResult(View view,HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{ String path = view.getPath(); if(StringUtil.isNotEmpty(path)){ if(path.startsWith("/")){ response.sendRedirect(request.getContextPath() + path); }else{ Map<String,Object> model = view.getModel(); for(Map.Entry<String, Object> entry : model.entrySet()){ request.setAttribute(entry.getKey(), entry.getValue()); } request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(request, response); } } } private void handleDataResult(Data data,HttpServletResponse response)throws IOException{ Object model = data.getModel(); if(model != null){ response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); String json = JsonUtil.toJson(model); writer.write(json); writer.flush(); writer.close(); } } }加载类,通过class.forName()。参考代码如下:
package com.light.framework; import com.light.framework.helper.AopHelper; import com.light.framework.helper.BeanHelper; import com.light.framework.helper.ClassHelper; import com.light.framework.helper.ControllerHelper; import com.light.framework.helper.IocHelper; import com.light.framework.util.ClassUtil; /** * 加载响应的Helper类 * @author wenjie * @since 1.0.0 */ public final class HelperLoader { public static void init(){ //需要注意AopHelper要在IocHelper之前加载,因为首先需要通过AopHelper获取代理对象,然后才能通过IocHelper进行依赖注入 Class<?>[] classList = { ClassHelper.class, BeanHelper.class, AopHelper.class, IocHelper.class, ControllerHelper.class, }; for(Class<?> cls : classList){ ClassUtil.loadClass(cls.getName()); //通过类的全限定名加载类 } } }(2)ClassHelper类:用于获取应用包名下的类(所有类,Service类,Controller类,其他的带有某注解的类)
package com.light.framework.helper; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.Set; import com.light.framework.util.ClassUtil; import com.ligth.framework.annotation.Service; import com.ligth.framework.annotation.Controller; /** * 类操作助手类 */ public class ClassHelper { /** * 定义类集合(存放所加载的类) */ private static final Set<Class<?>> CLASS_SET; static { String basePackage = ConfigHelper.getAppBasePackage(); CLASS_SET = ClassUtil.getClassSet(basePackage); } /** * 获取应用包名下的所有类 */ public static Set<Class<?>> getClassSet(){ return CLASS_SET; } /** * 获取应用包名下所有Service类 */ public static Set<Class<?>> getServiceClassSet(){ Set<Class<?>> classSet = new HashSet<Class<?>>(); for(Class<?> cls : CLASS_SET){ if(cls.isAnnotationPresent(Service.class)){ classSet.add(cls); } } return classSet; } /** * 获取应用包名下所有Controller类 */ public static Set<Class<?>> getControllerClassSet(){ Set<Class<?>> classSet = new HashSet<Class<?>>(); for(Class<?> cls : CLASS_SET){ if(cls.isAnnotationPresent(Controller.class)){ classSet.add(cls); } } return classSet; } /** * 获取应用包名下所有bean类(包括Service,Controller等) */ public static Set<Class<?>> getBeanClassSet(){ Set<Class<?>> beanClassSet = new HashSet<Class<?>>(); beanClassSet.addAll(getServiceClassSet()); beanClassSet.addAll(getControllerClassSet()); return beanClassSet; } /** * 获取应用包名下某父类(或者接口)的所有子类(或者实现类) */ public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) { Set<Class<?>> classSet = new HashSet<Class<?>>(); for (Class<?> cls : CLASS_SET) { // 此Class对象所表示的类或接口是否相同,前后则关系是父与子关系或接口与被实现关系,但又不同名 // 关系是 父亲.isAssignableFrom(子) if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) { classSet.add(cls); } } return classSet; } /** * 获取应用包名下带有某注解的所有类比如获取所有注解(Annotation)是Controller的类(即所有的控制器类,就是切面类要管理的目标类) */ public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) { Set<Class<?>> classSet = new HashSet<Class<?>>(); for (Class<?> cls : CLASS_SET) { if (cls.isAnnotationPresent(annotationClass)) { classSet.add(cls); } } return classSet; } }其中获得类的扩展方法为:
package com.light.framework.util; import java.io.File; import java.io.FileFilter; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.light.framework.util.StringUtil; /** * @ClassName: ClassUtil * @Description: 类工具 * @author wenjie */ public final class ClassUtil { private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class); /** * 获取类加载器 */ public static ClassLoader getClassLoader(){ return Thread.currentThread().getContextClassLoader(); } /** * 加载类,为了提高加载性能,可将isInitialized设为false */ public static Class<?> loadClass(String className,boolean isInitialized){ Class<?> cls; try{ cls = Class.forName(className,isInitialized,getClassLoader()); }catch (ClassNotFoundException e) { LOGGER.error("load class failure",e); throw new RuntimeException(e); } return cls; } /** * 加载类,为了提高加载性能,可将isInitialized设为false * ,则不会加载该类的静态块,使得Bean没有被初始化,如果使用则报空指针错误。 * 所以,如果要使用则isInitialized设为true */ public static Class<?> loadClass(String className){ Class<?> cls; try{ cls = Class.forName(className,true,getClassLoader()); }catch (Exception e) { LOGGER.error("load class failure",e); throw new RuntimeException(e); } return cls; } /** * 获取指定包名下的所有类 */ public static Set<Class<?>> getClassSet(String packageName){ Set<Class<?>> classSet = new HashSet<Class<?>>(); try{ Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/")); while(urls.hasMoreElements()){ URL url = urls.nextElement(); if(url != null){ String protocol = url.getProtocol(); if(protocol.equals("file")){ String packagePath = url.getPath().replaceAll("%20", " "); addClass(classSet,packagePath,packageName); }else if(protocol.equals("jar")){ JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection(); if(jarURLConnection != null){ JarFile jarFile = jarURLConnection.getJarFile(); if(jarFile != null){ Enumeration<JarEntry> jarEntries = jarFile.entries(); while(jarEntries.hasMoreElements()){ JarEntry jarEntry = jarEntries.nextElement(); String jarEntryName = jarEntry.getName(); //System.out.println(" jarEntryName------------------ > " + jarEntryName); if(jarEntryName.endsWith(".class")){ String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replace("/", "."); doAddClass(classSet,className); } } } } } } } }catch (Exception e) { LOGGER.error("load class set failure",e); throw new RuntimeException(e); } return classSet; } private static void addClass(Set<Class<?>> classSet,String packagePath,String packageName){ File[] files = new File(packagePath).listFiles(new FileFilter() { @Override public boolean accept(File file) { //只要class文件或者目录,其他文件不要 return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory(); } }); for(File file : files){ String fileName = file.getName(); if(file.isFile()){ String className = fileName.substring(0,fileName.lastIndexOf(".")); if(StringUtil.isNotEmpty(packageName)){ className = packageName + "." + className; } doAddClass(classSet,className); }else{ String subPackagePath = fileName; if(StringUtil.isNotEmpty(packagePath)){ subPackagePath = packagePath + "/" + subPackagePath; } String subPackageName = fileName; if(StringUtil.isNotEmpty(packageName)){ subPackageName = packageName + "." + subPackageName; } addClass(classSet,subPackagePath,subPackageName); } } } public static void doAddClass(Set<Class<?>> classSet,String className){ Class<?> cls = loadClass(className,false); if(cls != null){ classSet.add(cls); } } }(3)BeanHelper类:主要用于存放Bean类与Bean实例的映射关系
package com.light.framework.helper; import java.util.HashMap; import java.util.Map; import java.util.Set; import com.light.framework.util.ReflectionUtil; /** * Bean助手类 * @author wenjie * @since 1.0.0 */ public final class BeanHelper { /** * 定义Bean映射(用于存放Bean类与Bean实例的映射关系) */ private static final Map<Class<?>,Object> BEAN_MAP = new HashMap<Class<?>, Object>(); static{ Set<Class<?>> beanClassSet = ClassHelper.getBeanClassSet(); for(Class<?> beanclass : beanClassSet){ Object obj = ReflectionUtil.newInstance(beanclass);//实例化类 BEAN_MAP.put(beanclass, obj); //使用map创建一个类名与类实例的一个映射关系 } //System.out.println("BEAN_MAP:"+BEAN_MAP.size()); } /** * 获取Bean映射 */ public static Map<Class<?>,Object> getBeanMap(){ return BEAN_MAP; } /** * 获取Bean实例 */ @SuppressWarnings("unchecked") public static <T> T getBean(Class<T> cls){ if(!BEAN_MAP.containsKey(cls)){ throw new RuntimeException("can not get bean by class: " + cls); } return (T) BEAN_MAP.get(cls); } /** * 设置Bean实例 */ public static void setBean(Class<?> cls, Object obj){ BEAN_MAP.put(cls, obj); } }(4)AopHelper类:切面辅助类,用于初始化AOP框架
package com.light.framework.helper; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.light.framework.proxy.AspectProxy; import com.light.framework.proxy.Proxy; import com.light.framework.proxy.ProxyManager; import com.light.framework.proxy.TransactionProxy; import com.ligth.framework.annotation.Aspect; import com.ligth.framework.annotation.Service; public final class AopHelper { private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class); /** * 静态块初始化AOP框架 */ static{ try{ //代理类和目标类集合的映射关系Map,包含普通切面类和事务切面类 Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap(); //key-value 转换 即目标类(被切类)- 切面类 Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap); for(Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()){ //目标类 Class<?> targetClass = targetEntry.getKey(); //System.out.println(targetClass.getName()); //切面类,有可能一个目标类有多个切面类,比如权限切面、日志切面等 List<Proxy> proxyList = targetEntry.getValue(); //动态生成某个类具体的切面(代理)类 Object proxy = ProxyManager.createProxy(targetClass, proxyList); BeanHelper.setBean(targetClass, proxy); } }catch (Exception e) { LOGGER.error("aop failure",e); } } /** * 获取注解类是aspect.value()的所有类,比如aspect.value()=Controller ,那就是所有带注解是Controller类的 */ private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception{ Set<Class<?>> targetClassSet = new HashSet<Class<?>>(); //其实就是Aspect注解 Class<? extends Annotation> annotation = aspect.value(); if(annotation != null && !annotation.equals(Aspect.class)){ //比如aspect.value()是 controller,那么本此的目标类就是注解是Controller的类(所有的控制器类) targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation)); } return targetClassSet; } /** * 获取目标类和代理类的映射关系 */ private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception{ Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>(); //表示继承了AspectProxy 的类可能会是代理类,下面会过滤,如果Annotation是Aspect那么就是代理类 /* Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); for(Class<?> proxyClass : proxyClassSet){ if(proxyClass.isAnnotationPresent(Aspect.class)){ Aspect aspect = proxyClass.getAnnotation(Aspect.class); Set<Class<?>> targetClassSet = createTargetClassSet(aspect); proxyMap.put(proxyClass, targetClassSet); } }*/ addAspectProxy(proxyMap); addTransactionProxy(proxyMap); return proxyMap; } /** * 根据映射关系分析目标类和代理对象列表之间的映射关系(key-value 转换) * 将原来的1个切面类对应一个被切类(委托类)集合变换成1个被切类(目标类OR被代理类) * 对应一个切面类(代理类),也就是添加一一对应关系可以直接从Map中找到 */ private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{ Map<Class<?>,List<Proxy>> targetMap = new HashMap<Class<?>,List<Proxy>>(); for(Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()){ //切面类 Class<?> proxyClass = proxyEntry.getKey(); //被切类 Set<Class<?>> targetClassSet = proxyEntry.getValue(); for(Class<?> targetClass : targetClassSet){ //切面类实例 Proxy proxy = (Proxy) proxyClass.newInstance(); //如果目标类(被切类)已经包含了,则将该切面类的实例映射到该目标类上 if(targetMap.containsKey(targetClass)){ targetMap.get(targetClass).add(proxy); }else{ List<Proxy> proxyList = new ArrayList<Proxy>(); proxyList.add(proxy); targetMap.put(targetClass, proxyList); } } } return targetMap; } /** * 添加普通切面代理 */ private static void addAspectProxy(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{ //普通切面类必须是继承AspectProxy,获取所有切面类 Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class); for(Class<?> proxyClass : proxyClassSet){ //普通切面类必须是有Aspect的标识,获取所有切面类 if(proxyClass.isAnnotationPresent(Aspect.class)){ //获取Aspect的值,即获取该切面类要横切的对象或者哪一类对象 //(比如@Aspect(Controller.class) 表示该切面类横切带Controller注解的类,即控制器类) Aspect aspect = proxyClass.getAnnotation(Aspect.class); //创建被横切的类,比如所有的Controller类 Set<Class<?>> targetClassSet = createTargetClassSet(aspect); proxyMap.put(proxyClass,targetClassSet); } } } /** * 添加事务切面代理 */ private static void addTransactionProxy(Map<Class<?>,Set<Class<?>>> proxyMap){ Set<Class<?>> serviceClassSet = ClassHelper.getClassSetByAnnotation(Service.class); proxyMap.put(TransactionProxy.class, serviceClassSet); } }(5)IocHelper类:依赖注入类,通过遍历BeanMap,找出Field中带有Inject注解的成员变量,然后通过反射进行初始化
package com.light.framework.helper; import java.lang.reflect.Field; import java.util.Map; import com.light.framework.util.ArrayUtil; import com.light.framework.util.CollectionUtil; import com.light.framework.util.ReflectionUtil; import com.ligth.framework.annotation.Inject; /** * 依赖注入助手类 * @author wenjie * @since 1.0.0 */ public final class IocHelper { static{ //获取所有的Bean类与Bean实例之间的映射关系(简称 Bean Map) Map<Class<?>,Object> beanMap = BeanHelper.getBeanMap(); if(CollectionUtil.isNotEmpty(beanMap)){ //遍历Bean Map for(Map.Entry<Class<?>, Object>beanEntry : beanMap.entrySet()){ //从BeanMap 中获取Bean类与Bean实例 Class<?> beanClass = beanEntry.getKey(); Object beanInstance = beanEntry.getValue(); //获取Bean 类定义的所有成员变量(简称Bean Field) Field[] beanFields = beanClass.getDeclaredFields(); if(ArrayUtil.isNotEmpty(beanFields)){ //遍历Bean Field for(Field beanField : beanFields){ //判断当前Bean Field 是否 带有 Inject 注解 if(beanField.isAnnotationPresent(Inject.class)){ //System.out.println("当前方法"+beanField); //在Bean Map中获取Bean Field对应的实例 Class<?> beanFieldClass = beanField.getType(); Object beanFieldInstance = beanMap.get(beanFieldClass); if(beanFieldInstance != null){ //通过反射初始化BeanField的值 将某属性值设置到对应的实例化对象中 ReflectionUtil.setField(beanInstance, beanField, beanFieldInstance); } } } } } } } }相当于对属性进行一个属性注入的过程。首先获得bean,然后得到bean的实例对象,通过反射得到成员变量,注入。
(6)ControllerHelper类:用于存放请求和处理器的映射关系
package com.light.framework.helper; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.light.framework.bean.Handler; import com.light.framework.bean.Request; import com.light.framework.util.ArrayUtil; import com.light.framework.util.CollectionUtil; import com.ligth.framework.annotation.Action; /** * 控制器助手类 * @author wenjie * @since 1.0.0 */ public final class ControllerHelper { //用于存放请求与处理器映射关系(简称Action Map) private static final Map<Request,Handler> ACTION_MAP = new HashMap<Request,Handler>(); static{ //获取所有的Controller类 Set<Class<?>> controllerClassSet = ClassHelper.getControllerClassSet(); if(CollectionUtil.isNotEmpty(controllerClassSet)){ for(Class<?> controllerClass : controllerClassSet){ //获取Controller类中定义的方法 Method[] methods = controllerClass.getDeclaredMethods(); if(ArrayUtil.isNotEmpty(methods)){ //遍历这些Controller中的方法 for(Method method : methods){ //判断当前方法是否带有Action 注解 if(method.isAnnotationPresent(Action.class)){ //从Action注解中获取URL 映射规则 Action action = method.getAnnotation(Action.class); String mapping = action.value(); //验证URL映射规则 if(mapping.matches("\\w+:/\\w*")){ String[] array = mapping.split(":"); if(ArrayUtil.isNotEmpty(array) && array.length == 2){ //获取请求方法与请求路径 String requestMethod = array[0]; String requestPath = array[1]; Request request = new Request(requestMethod, requestPath); Handler handler = new Handler(controllerClass, method); //初始化Action Map ACTION_MAP.put(request, handler); } } } } } } } } /** * 获取Handler */ public static Handler getHandler(String requestMethod,String requestPath){ Request request = new Request(requestMethod, requestPath); return ACTION_MAP.get(request); } }其实就是获得Controller bean,查看注解中的Action,得到他的映射地址,处理方法等。
项目优化:
(1)使用ThreadLocal来存放JDBC Connection (2)增加事务控制特性
package com.light.framework.proxy; import java.lang.reflect.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.light.framework.helper.DatabaseHelper; import com.ligth.framework.annotation.Transaction; /** * 事务代理 * @author wenjie * @since 1.0.0 */ public class TransactionProxy implements Proxy { private static final Logger LOGGER = LoggerFactory.getLogger(TransactionProxy.class); //保证同一线程中事务控制相关逻辑只会执行一次 private static final ThreadLocal<Boolean> FLAG_HOLDER = new ThreadLocal<Boolean>(){ @Override protected Boolean initialValue(){ return false; } }; @Override public Object doProxy(ProxyChain proxyChain) throws Throwable{ Object result = null; boolean flag = FLAG_HOLDER.get(); Method method = proxyChain.getTargetMethod(); if(!flag && method.isAnnotationPresent(Transaction.class)){ FLAG_HOLDER.set(true); try{ DatabaseHelper.beginTransaction(); //增加了事务处理 LOGGER.debug("begin transaction"); result = proxyChain.doProxyChain(); DatabaseHelper.commitTransaction(); LOGGER.debug("commit transaction"); } catch(Exception e){ DatabaseHelper.rollbackTransaction(); LOGGER.debug("rollback transaction"); } finally{ FLAG_HOLDER.remove(); } } else{ result = proxyChain.doProxyChain(); } return result; } }
package com.light.framework.helper; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.light.framework.util.CollectionUtil; import com.light.framework.util.PropsUtil; /** * 数据库操作助手类 */ public final class DatabaseHelper { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class); private static final QueryRunner QUERY_RUNNER; private static final BasicDataSource DATA_SOURCE; //利用ThreadLocal来存储connection private static final ThreadLocal<Connection> CONNECTION_HOLDER; /** * 数据库相关配置信息 */ private static final String DRIVER; private static final String URL; private static final String USERNAME; private static final String PASSWORD; static{ CONNECTION_HOLDER = new ThreadLocal<Connection>(); QUERY_RUNNER = new QueryRunner(); Properties conf = PropsUtil.LoadProps("light.properties"); DRIVER = conf.getProperty("light.framework.jdbc.driver"); URL = conf.getProperty("light.framework.jdbc.url"); USERNAME = conf.getProperty("light.framework.jdbc.username"); PASSWORD = conf.getProperty("light.framework.jdbc.password"); DATA_SOURCE = new BasicDataSource(); DATA_SOURCE.setDriverClassName(DRIVER); DATA_SOURCE.setUrl(URL); DATA_SOURCE.setUsername(USERNAME); DATA_SOURCE.setPassword(PASSWORD); try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { LOGGER.error("can not load jdbc driver",e); } } /** * 获取数据库连接 */ public static Connection getConnection(){ Connection conn = CONNECTION_HOLDER.get(); if(conn == null){ try { //conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); conn = DATA_SOURCE.getConnection(); } catch (SQLException e) { LOGGER.error("get connection fail",e); throw new RuntimeException(e); } finally { CONNECTION_HOLDER.set(conn); } } return conn; } /** * 关闭数据库连接 */ @Deprecated public static void closeConnection(){ Connection conn = CONNECTION_HOLDER.get(); if(conn != null){ try { conn.close(); } catch (SQLException e) { LOGGER.error("close connection fail",e); throw new RuntimeException(e); } finally{ CONNECTION_HOLDER.remove(); } } } /** * 开启事务 */ public static void beginTransaction(){ Connection conn = getConnection(); if(conn != null){ try { conn.setAutoCommit(false); } catch (SQLException e) { LOGGER.error("begin transaction fail",e); throw new RuntimeException(e); } finally{ CONNECTION_HOLDER.set(conn); } } } /** * 提交事务 */ public static void commitTransaction(){ Connection conn = getConnection(); if(conn != null){ try { conn.commit(); conn.close(); } catch (SQLException e) { LOGGER.error("commit transaction fail",e); throw new RuntimeException(e); } } } /** * 事务回滚 */ public static void rollbackTransaction(){ Connection conn = getConnection(); if(conn != null){ try { conn.rollback(); conn.close(); } catch (SQLException e) { LOGGER.error("rollback transaction fail",e); throw new RuntimeException(e); } } } /** * 查询实例列表 */ public static <T> List<T> queryEntityList(Class<T> entityClass, String sql,Object... params) { List<T> entityList; try { Connection conn = getConnection(); entityList = QUERY_RUNNER.query(conn, sql, new BeanListHandler<T>(entityClass), params); } catch (SQLException e) { LOGGER.error("query entity list failure", e); throw new RuntimeException(e); } return entityList; } /** * 查询单个实体对象 */ public static <T> T queryEntity(Class<T> entityClass,String sql,Object... params){ T entity; try{ Connection conn = getConnection(); entity = QUERY_RUNNER.query(conn, sql,new BeanHandler<T>(entityClass),params); }catch (SQLException e) { LOGGER.error("query entity failure",e); throw new RuntimeException(e); } return entity; } /** * 执行查询语句 */ public static List<Map<String,Object>> executeQuery(String sql, Object ...params){ List<Map<String,Object>> result = null; try { Connection conn = getConnection(); QUERY_RUNNER.query(conn, sql, new MapListHandler(), params); } catch (SQLException e) { LOGGER.error("execute query fail"); throw new RuntimeException(e); } return result; } /** * 执行更新语句(包括update,insert,delete) */ public static int executeUpdate(String sql,Object...objects){ int rows = 0; try{ Connection conn = getConnection(); rows = QUERY_RUNNER.update(conn,sql,objects); }catch (SQLException e) { LOGGER.error("execute update failure",e); } return rows; } /** * @Title: insertEntity * @Description: 插入实体 * @param @param entityClass * @param @param fieldMap * @param @return 设定文件 * @return boolean 返回类型 * @throws */ public static <T> boolean insertEntity(Class<T> entityClass,Map<String,Object> fieldMap){ if(CollectionUtil.isEmpty(fieldMap)){ LOGGER.error("can not insert entity: fieldMap is empty"); return false; } String sql = "insert into " + getTableName(entityClass); StringBuilder columns = new StringBuilder("("); StringBuilder values = new StringBuilder("("); for(String fieldName : fieldMap.keySet()){ columns.append(fieldName).append(", "); values.append("?, "); } //columns 将最后一个, 换成) columns.replace(columns.lastIndexOf(", "),columns.length(),")"); //values 将最后一个, 换成) values.replace(values.lastIndexOf(", "), values.length(), ")"); sql += columns + " values " + values; Object[] params = fieldMap.values().toArray(); return executeUpdate(sql,params) == 1; } /** * @Title: updateEntity * @Description: 更新实体 * @param @param entityClass * @param @param id * @param @param fieldMap * @param @return 设定文件 * @return boolean 返回类型 * @throws */ public static <T> boolean updateEntity(Class<T> entityClass,long id,Map<String,Object> fieldMap){ if(CollectionUtil.isEmpty(fieldMap)){ LOGGER.error("can not update entity: fieldMap is empty"); return false; } String sql = " update " + getTableName(entityClass) + " set "; StringBuilder columns = new StringBuilder(); for(String fieldName : fieldMap.keySet()){ columns.append(fieldName).append("=?, "); } sql += columns.substring(0, columns.lastIndexOf(", ")) + " where id = ?"; List<Object> paramList = new ArrayList<Object>(); paramList.addAll(fieldMap.values()); paramList.add(id); Object[] params = paramList.toArray(); return executeUpdate(sql,params) == 1; } /** * @Title: deleteEntity * @Description: 删除实体 * @param @param entityClass * @param @param id * @param @return 设定文件 * @return boolean 返回类型 * @throws */ public static <T> boolean deleteEntity(Class<T> entityClass,long id){ String sql = " delete from " + getTableName(entityClass) + " where id=?"; return executeUpdate(sql, id) == 1; } /** * @Title: getTableName * @Description: 获取表名(实体类名,要求数据库表名和实体类名相同) * @param @param entityClass * @param @return 设定文件 * @return String 返回类型 * @throws */ public static String getTableName(Class<?> entityClass){ return entityClass.getSimpleName(); } }
Aop是使用代理链实现的。事务也是利用代理链。
TODO: (1)增加Shiro (2)增加Web服务框架(计划使用CXF)