Hessian源码分析和Hack --让Hessian携带远程调用端的信息(上)-程序员宅基地

技术标签: 转载  java  RPC  web.xml  分布式系统架构  

项目选定Hessian作为web service的实现方式,确实很轻量级,速度就跟直接用socket差不多,全是二进制传送节约了不少开销。但是在使用过程中有业务需要是必须获得远程端的ip地址,主机名等信息的。翻便Hessian的文档和google了n次未果,迫不得已到caucho和spring论坛去问,都没有得到答复。今天心一横把hessian的源代码加入到项目中单步跟踪,总算有点小收获。献丑分享出来,一方面给需要的朋友,主要还是希望各位找找是否存在bug,以及是否有更好的改良。 

一:先撇开Spring不谈,来看看纯Hessian的调用 
按照hessian文档里边介绍的demo,在web.xml里边如下配置 

Java代码   收藏代码
  1.  <servlet>  
  2.  <servlet-name>hello</servlet-name>  
  3.  <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>  
  4.   <init-param>  
  5.     <param-name>home-class</param-name>  
  6.     <param-value>example.BasicService</param-value>  
  7.   </init-param>  
  8.   <init-param>  
  9.     <param-name>home-api</param-name>  
  10.     <param-value>example.Basic</param-value>  
  11.   </init-param>  
  12. </servlet>  
  13.   
  14. <servlet-mapping>  
  15.   <url-pattern>/hello</url-pattern>  
  16.   <servlet-name>hello</servlet-name>  
  17. </servlet-mapping>  



由此可知Hessian调用的入口是HessianServlet这个Servlet,进去看看 

Java代码   收藏代码
  1. /** 
  2.  * Servlet for serving Hessian services. 
  3.  */  
  4. public class HessianServlet extends GenericServlet {  
  5.   private Class _homeAPI;  
  6.   private Object _homeImpl;  
  7.     
  8.   private Class _objectAPI;  
  9.   private Object _objectImpl;  
  10.     
  11.   private HessianSkeleton _homeSkeleton;  
  12.   private HessianSkeleton _objectSkeleton;  
  13.   
  14.   private SerializerFactory _serializerFactory;  
  15.   
  16.   public String getServletInfo()  
  17.   {  
  18.     return "Hessian Servlet";  
  19.   }  
  20.   
  21.   /** 
  22.    * Sets the home api. 
  23.    */  
  24.   public void setHomeAPI(Class api)  
  25.   {  
  26.     _homeAPI = api;  
  27.   }  
  28.   
  29.   /** 
  30.    * Sets the home implementation 
  31.    */  
  32.   public void setHome(Object home)  
  33.   {  
  34.     _homeImpl = home;  
  35.   }  
  36.   
  37.   /** 
  38.    * Sets the object api. 
  39.    */  
  40.   public void setObjectAPI(Class api)  
  41.   {  
  42.     _objectAPI = api;  
  43.   }  
  44.   
  45.   /** 
  46.    * Sets the object implementation 
  47.    */  
  48.   public void setObject(Object object)  
  49.   {  
  50.     _objectImpl = object;  
  51.   }  
  52.   
  53.   /** 
  54.    * Sets the service class. 
  55.    */  
  56.   public void setService(Object service)  
  57.   {  
  58.     setHome(service);  
  59.   }  
  60.   
  61.   /** 
  62.    * Sets the api-class. 
  63.    */  
  64.   public void setAPIClass(Class api)  
  65.   {  
  66.     setHomeAPI(api);  
  67.   }  
  68.   
  69.   /** 
  70.    * Gets the api-class. 
  71.    */  
  72.   public Class getAPIClass()  
  73.   {  
  74.     return _homeAPI;  
  75.   }  
  76.   
  77.   /** 
  78.    * Sets the serializer factory. 
  79.    */  
  80.   public void setSerializerFactory(SerializerFactory factory)  
  81.   {  
  82.     _serializerFactory = factory;  
  83.   }  
  84.   
  85.   /** 
  86.    * Gets the serializer factory. 
  87.    */  
  88.   public SerializerFactory getSerializerFactory()  
  89.   {  
  90.     if (_serializerFactory == null)  
  91.       _serializerFactory = new SerializerFactory();  
  92.   
  93.     return _serializerFactory;  
  94.   }  
  95.   
  96.   /** 
  97.    * Sets the serializer send collection java type. 
  98.    */  
  99.   public void setSendCollectionType(boolean sendType)  
  100.   {  
  101.     getSerializerFactory().setSendCollectionType(sendType);  
  102.   }  
  103.   
  104.   /** 
  105.    * Initialize the service, including the service object. 
  106.    */  
  107.   public void init(ServletConfig config)  
  108.     throws ServletException  
  109.   {  
  110.     super.init(config);  
  111.       
  112.     try {  
  113.       if (_homeImpl != null) {  
  114.       }  
  115.       else if (getInitParameter("home-class") != null) {  
  116.     String className = getInitParameter("home-class");  
  117.       
  118.     Class homeClass = loadClass(className);  
  119.   
  120.     _homeImpl = homeClass.newInstance();  
  121.   
  122.     init(_homeImpl);  
  123.       }  
  124.       else if (getInitParameter("service-class") != null) {  
  125.     String className = getInitParameter("service-class");  
  126.       
  127.     Class homeClass = loadClass(className);  
  128.   
  129.     _homeImpl = homeClass.newInstance();  
  130.       
  131.     init(_homeImpl);  
  132.       }  
  133.       else {  
  134.     if (getClass().equals(HessianServlet.class))  
  135.       throw new ServletException("server must extend HessianServlet");  
  136.   
  137.     _homeImpl = this;  
  138.       }  
  139.   
  140.       if (_homeAPI != null) {  
  141.       }  
  142.       else if (getInitParameter("home-api") != null) {  
  143.     String className = getInitParameter("home-api");  
  144.       
  145.     _homeAPI = loadClass(className);  
  146.       }  
  147.       else if (getInitParameter("api-class") != null) {  
  148.     String className = getInitParameter("api-class");  
  149.   
  150.     _homeAPI = loadClass(className);  
  151.       }  
  152.       else if (_homeImpl != null) {  
  153.     _homeAPI = findRemoteAPI(_homeImpl.getClass());  
  154.   
  155.     if (_homeAPI == null)  
  156.       _homeAPI = _homeImpl.getClass();  
  157.       }  
  158.         
  159.       if (_objectImpl != null) {  
  160.       }  
  161.       else if (getInitParameter("object-class") != null) {  
  162.     String className = getInitParameter("object-class");  
  163.       
  164.     Class objectClass = loadClass(className);  
  165.   
  166.     _objectImpl = objectClass.newInstance();  
  167.   
  168.     init(_objectImpl);  
  169.       }  
  170.   
  171.       if (_objectAPI != null) {  
  172.       }  
  173.       else if (getInitParameter("object-api") != null) {  
  174.     String className = getInitParameter("object-api");  
  175.       
  176.     _objectAPI = loadClass(className);  
  177.       }  
  178.       else if (_objectImpl != null)  
  179.     _objectAPI = _objectImpl.getClass();  
  180.   
  181.       _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI);  
  182.       if (_objectAPI != null)  
  183.     _homeSkeleton.setObjectClass(_objectAPI);  
  184.   
  185.       if (_objectImpl != null) {  
  186.     _objectSkeleton = new HessianSkeleton(_objectImpl, _objectAPI);  
  187.     _objectSkeleton.setHomeClass(_homeAPI);  
  188.       }  
  189.       else  
  190.     _objectSkeleton = _homeSkeleton;  
  191.     } catch (ServletException e) {  
  192.       throw e;  
  193.     } catch (Exception e) {  
  194.       throw new ServletException(e);  
  195.     }  
  196.   }  
  197.   
  198.   private Class findRemoteAPI(Class implClass)  
  199.   {  
  200.     if (implClass == null || implClass.equals(GenericService.class))  
  201.       return null;  
  202.       
  203.     Class []interfaces = implClass.getInterfaces();  
  204.   
  205.     if (interfaces.length == 1)  
  206.       return interfaces[0];  
  207.   
  208.     return findRemoteAPI(implClass.getSuperclass());  
  209.   }  
  210.   
  211.   private Class loadClass(String className)  
  212.     throws ClassNotFoundException  
  213.   {  
  214.     ClassLoader loader = Thread.currentThread().getContextClassLoader();  
  215.   
  216.     if (loader != null)  
  217.       return Class.forName(className, false, loader);  
  218.     else  
  219.       return Class.forName(className);  
  220.   }  
  221.   
  222.   private void init(Object service)  
  223.     throws ServletException  
  224.   {  
  225.     if (service instanceof Service)  
  226.       ((Service) service).init(getServletConfig());  
  227.     else if (service instanceof Servlet)  
  228.       ((Servlet) service).init(getServletConfig());  
  229.   }  
  230.     
  231.   /** 
  232.    * Execute a request.  The path-info of the request selects the bean. 
  233.    * Once the bean's selected, it will be applied. 
  234.    */  
  235.   public void service(ServletRequest request, ServletResponse response)  
  236.     throws IOException, ServletException  
  237.   {  
  238.     HttpServletRequest req = (HttpServletRequest) request;  
  239.     HttpServletResponse res = (HttpServletResponse) response;  
  240.   
  241.     if (! req.getMethod().equals("POST")) {  
  242.       res.setStatus(500"Hessian Requires POST");  
  243.       PrintWriter out = res.getWriter();  
  244.   
  245.       res.setContentType("text/html");  
  246.       out.println("<h1>Hessian Requires POST</h1>");  
  247.         
  248.       return;  
  249.     }  
  250.   
  251.     String serviceId = req.getPathInfo();  
  252.     String objectId = req.getParameter("id");  
  253.     if (objectId == null)  
  254.       objectId = req.getParameter("ejbid");  
  255.   
  256.     ServiceContext.begin(req, serviceId, objectId);  
  257.   
  258.     try {  
  259.       InputStream is = request.getInputStream();  
  260.       OutputStream os = response.getOutputStream();  
  261.   
  262.       Hessian2Input in = new Hessian2Input(is);  
  263.       AbstractHessianOutput out;  
  264.   
  265.       SerializerFactory serializerFactory = getSerializerFactory();  
  266.         
  267.       in.setSerializerFactory(serializerFactory);  
  268.   
  269.       int code = in.read();  
  270.   
  271.       if (code != 'c') {  
  272.     // XXX: deflate  
  273.     throw new IOException("expected 'c' in hessian input at " + code);  
  274.       }  
  275.   
  276.       int major = in.read();  
  277.       int minor = in.read();  
  278.   
  279.       if (major >= 2)  
  280.     out = new Hessian2Output(os);  
  281.       else  
  282.     out = new HessianOutput(os);  
  283.         
  284.       out.setSerializerFactory(serializerFactory);  
  285.   
  286.       if (objectId != null)  
  287.     _objectSkeleton.invoke(in, out);  
  288.       else  
  289.     _homeSkeleton.invoke(in, out);  
  290.   
  291.       out.close();  
  292.     } catch (RuntimeException e) {  
  293.       throw e;  
  294.     } catch (ServletException e) {  
  295.       throw e;  
  296.     } catch (Throwable e) {  
  297.       throw new ServletException(e);  
  298.     } finally {  
  299.       ServiceContext.end();  
  300.     }  
  301.   }  
  302. }  



先看init()函数,功能还是一样,初始话一些东西,读入init-param的内容,并且load这些init-param的class 

主要的还是service()函数 
在service函数里边会获得request和response对象的输入和输出流,用来构造Hessian2Input和Hessian2Output,Hessian就是解析这两个东西来执行函数调用的。当然,在service里边还有一个重要的语句 

Java代码   收藏代码
  1. ServiceContext.begin(req, serviceId, objectId);  


这个函数有点奇怪,我每次到这里serviceId和objectId都是空,不知道是不是历史遗留问题还存在这两个参数。 
进去这个类看看 

Java代码   收藏代码
  1. public class ServiceContext {  
  2.   private static final ThreadLocal _localContext = new ThreadLocal();  
  3.   
  4.   private ServletRequest _request;  
  5.   private String _serviceName;  
  6.   private String _objectId;  
  7.   private int _count;  
  8.   private HashMap _headers = new HashMap();  
  9.   
  10.   private ServiceContext()  
  11.   {  
  12.   }  
  13.     
  14.   /** 
  15.    * Sets the request object prior to calling the service's method. 
  16.    * 
  17.    * @param request the calling servlet request 
  18.    * @param serviceId the service identifier 
  19.    * @param objectId the object identifier 
  20.    */  
  21.   public static void begin(ServletRequest request,  
  22.                String serviceName,  
  23.                String objectId)  
  24.     throws ServletException  
  25.   {  
  26.     ServiceContext context = (ServiceContext) _localContext.get();  
  27.   
  28.     if (context == null) {  
  29.       context = new ServiceContext();  
  30.       _localContext.set(context);  
  31.     }  
  32.   
  33.     context._request = request;  
  34.     context._serviceName = serviceName;  
  35.     context._objectId = objectId;  
  36.     context._count++;  
  37.   }  
  38.   
  39.   /** 
  40.    * Returns the service request. 
  41.    */  
  42.   public static ServiceContext getContext()  
  43.   {  
  44.     return (ServiceContext) _localContext.get();  
  45.   }  
  46.   
  47.   /** 
  48.    * Adds a header. 
  49.    */  
  50.   public void addHeader(String header, Object value)  
  51.   {  
  52.     _headers.put(header, value);  
  53.   }  
  54.   
  55.   /** 
  56.    * Gets a header. 
  57.    */  
  58.   public Object getHeader(String header)  
  59.   {  
  60.     return _headers.get(header);  
  61.   }  
  62.   
  63.   /** 
  64.    * Gets a header from the context. 
  65.    */  
  66.   public static Object getContextHeader(String header)  
  67.   {  
  68.     ServiceContext context = (ServiceContext) _localContext.get();  
  69.   
  70.     if (context != null)  
  71.       return context.getHeader(header);  
  72.     else  
  73.       return null;  
  74.   }  
  75.   
  76.   /** 
  77.    * Returns the service request. 
  78.    */  
  79.   public static ServletRequest getContextRequest()  
  80.   {  
  81.     ServiceContext context = (ServiceContext) _localContext.get();  
  82.   
  83.     if (context != null)  
  84.       return context._request;  
  85.     else  
  86.       return null;  
  87.   }  
  88.   
  89.   /** 
  90.    * Returns the service id, corresponding to the pathInfo of the URL. 
  91.    */  
  92.   public static String getContextServiceName()  
  93.   {  
  94.     ServiceContext context = (ServiceContext) _localContext.get();  
  95.   
  96.     if (context != null)  
  97.       return context._serviceName;  
  98.     else  
  99.       return null;  
  100.   }  
  101.   
  102.   /** 
  103.    * Returns the object id, corresponding to the ?id= of the URL. 
  104.    */  
  105.   public static String getContextObjectId()  
  106.   {  
  107.     ServiceContext context = (ServiceContext) _localContext.get();  
  108.   
  109.     if (context != null)  
  110.       return context._objectId;  
  111.     else  
  112.       return null;  
  113.   }  
  114.   
  115.   /** 
  116.    * Cleanup at the end of a request. 
  117.    */  
  118.   public static void end()  
  119.   {  
  120.     ServiceContext context = (ServiceContext) _localContext.get();  
  121.   
  122.     if (context != null && --context._count == 0) {  
  123.       context._request = null;  
  124.   
  125.       context._headers.clear();  
  126.     }  
  127.   }  
  128.   
  129.   /** 
  130.    * Returns the service request. 
  131.    * 
  132.    * @deprecated 
  133.    */  
  134.   public static ServletRequest getRequest()  
  135.   {  
  136.     ServiceContext context = (ServiceContext) _localContext.get();  
  137.   
  138.     if (context != null)  
  139.       return context._request;  
  140.     else  
  141.       return null;  
  142.   }  
  143.   
  144.   /** 
  145.    * Returns the service id, corresponding to the pathInfo of the URL. 
  146.    * 
  147.    * @deprecated 
  148.    */  
  149.   public static String getServiceName()  
  150.   {  
  151.     ServiceContext context = (ServiceContext) _localContext.get();  
  152.   
  153.     if (context != null)  
  154.       return context._serviceName;  
  155.     else  
  156.       return null;  
  157.   }  
  158.   
  159.   /** 
  160.    * Returns the object id, corresponding to the ?id= of the URL. 
  161.    * 
  162.    * @deprecated 
  163.    */  
  164.   public static String getObjectId()  
  165.   {  
  166.     ServiceContext context = (ServiceContext) _localContext.get();  
  167.   
  168.     if (context != null)  
  169.       return context._objectId;  
  170.     else  
  171.       return null;  
  172.   }  
  173. }  



原来ServiceContext 是用来保存当前调用线程的上下文的,比如request对象等(不知道这个解释对不对)。有了这个东西就太好了,因为里边有request,就有了调用端的一切信息,呵呵。 

继续回来看那个Servlet,到了真正调用的时候了,也就是这段代码 

Java代码   收藏代码
  1. if (objectId != null)  
  2. ctSkeleton.invoke(in, out);  
  3. else  
  4. Skeleton.invoke(in, out);  



跟踪invoke方法看看真面目 

Java代码   收藏代码
  1. public void invoke(AbstractHessianInput in, AbstractHessianOutput out)  
  2.   throws Throwable  
  3. {  
  4.   ServiceContext context = ServiceContext.getContext();  
  5.     
  6.   String header;  
  7.   while ((header = in.readHeader()) != null) {  
  8.     Object value = in.readObject();  
  9.   
  10.     context.addHeader(header, value);  
  11.   }  
  12.   String ip = context.getContextRequest().getRemoteAddr();  
  13.   String methodName = in.readMethod();  
  14.   Method method = getMethod(methodName);  
  15.   
  16.   if (method != null) {  
  17.   }  
  18.   else if ("_hessian_getAttribute".equals(methodName)) {  
  19.     String attrName = in.readString();  
  20.     in.completeCall();  
  21.   
  22.     String value = null;  
  23.   
  24.     if ("java.api.class".equals(attrName))  
  25. alue = getAPIClassName();  
  26.     else if ("java.home.class".equals(attrName))  
  27. alue = getHomeClassName();  
  28.     else if ("java.object.class".equals(attrName))  
  29. alue = getObjectClassName();  
  30.   
  31.     out.startReply();  
  32.   
  33.     out.writeObject(value);  
  34.   
  35.     out.completeReply();  
  36.     return;  
  37.   }  
  38.   else if (method == null) {  
  39.     out.startReply();  
  40.     out.writeFault("NoSuchMethodException",  
  41.      "The service has no method named: " + in.getMethod(),  
  42.      null);  
  43.     out.completeReply();  
  44.     return;  
  45.   }  
  46.   
  47.   Class []args = method.getParameterTypes();  
  48.   Object []values = new Object[args.length];  
  49.     
  50.   //args[0]  
  51.   
  52.   for (int i = 0; i < args.length; i++){  
  53.     if(i == args.length-1){  
  54.         values[i] = in.readObject(args[i], ip);  
  55.     }else{  
  56.         values[i] = in.readObject(args[i]);  
  57.     }  
  58.       
  59.   }  
  60.       
  61.   
  62.   in.completeCall();  
  63.   
  64.   Object result = null;  
  65.     
  66.   try {  
  67.     result = method.invoke(_service, values);  
  68.   } catch (Throwable e) {  
  69.     if (e instanceof InvocationTargetException)  
  70.       e = ((InvocationTargetException) e).getTargetException();  
  71.   
  72.     log.log(Level.WARNING, e.toString(), e);  
  73.       
  74.     out.startReply();  
  75.     out.writeFault("ServiceException", e.getMessage(), e);  
  76.     out.completeReply();  
  77.     return;  
  78.   }  
  79.   
  80.   out.startReply();  
  81.   
  82.   out.writeObject(result);  
  83.     
  84.   out.completeReply();  
  85. }  



就是在这个方法里边,hessian把包装过的输入输出流当作参数传入并进行解析的,看看这个函数的第一句,正是取得ServiceContext的地方,此时应该就是把刚才Servlet里边保存的上下文取出来使用。 
这个时候出现了第一个hack的地方

Java代码   收藏代码
  1. String ip = context.getContextRequest().getRemoteAddr();  

在此处我取得远程的ip地址保存起来。然后在第二个hack的地方 

Java代码   收藏代码
  1. Class []args = method.getParameterTypes();  
  2. Object []values = new Object[args.length];  
  3.   
  4. //args[0]  
  5.   
  6. for (int i = 0; i < args.length; i++){  
  7.     if(i == args.length-1){  
  8.         values[i] = in.readObject(args[i], ip);  
  9.     }else{  
  10.         values[i] = in.readObject(args[i]);  
  11.     }  
  12.       
  13. }  


我用这个ip地址取代最后一个参数(web服务函数的参数,即远程端调用的函数的参数)。 
第三个hack的地方就是 in.readObject(args[i], ip); 这个方法。 这个方法是我自己加的,原本只有 
in.readObject(args[i]); 这个方法。 这个方法就是hessian读取参数值的地方 
进去看看 

Java代码   收藏代码
  1. /** 
  2.  * Reads an object from the input stream with an expected type. 
  3.  */  
  4. public Object readObject(Class cl, String ip)  
  5.   throws IOException  
  6. {  
  7.   if (cl == null || cl == Object.class)  
  8.     return readObject();  
  9.     
  10.   int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();  
  11.   
  12.   switch (tag) {  
  13.   case 'N':  
  14.     return null;  
  15.   
  16.   case 'M':  
  17.   {  
  18.     String type = readType();  
  19.     Deserializer reader;  
  20.     reader = findSerializerFactory().getObjectDeserializer(type);  
  21.   
  22.     if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))  
  23.       return reader.readMap(this);  
  24.   
  25.     reader = findSerializerFactory().getDeserializer(cl);  
  26.   
  27.     return reader.readMap(this);  
  28.   }  
  29.   
  30.   case 'O':  
  31.   {  
  32.     return readObjectDefinition(cl);  
  33.   }  
  34.   
  35.   case 'o':  
  36.   {  
  37.     int ref = readInt();  
  38.   
  39.     ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref - 1);  
  40.   
  41.     return readObjectInstance(cl, def);  
  42.   }  
  43.   
  44.   case 'V':  
  45.   {  
  46.     String type = readType();  
  47.     int length = readLength();  
  48.       
  49.     Deserializer reader;  
  50.     reader = findSerializerFactory().getObjectDeserializer(type);  
  51.       
  52.     if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))  
  53.       return reader.readList(this, length);  
  54.   
  55.     reader = findSerializerFactory().getDeserializer(cl);  
  56.   
  57.     Object v = reader.readList(this, length);  
  58.   
  59.     return v;  
  60.   }  
  61.   
  62.   case 'v':  
  63.   {  
  64.     int ref = readInt();  
  65.     String type = (String) _types.get(ref);  
  66.     int length = readInt();  
  67.       
  68.     Deserializer reader;  
  69.     reader = findSerializerFactory().getObjectDeserializer(type);  
  70.       
  71.     if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))  
  72.       return reader.readLengthList(this, length);  
  73.   
  74.     reader = findSerializerFactory().getDeserializer(cl);  
  75.   
  76.     Object v = reader.readLengthList(this, length);  
  77.   
  78.     return v;  
  79.   }  
  80.   
  81.   case 'R':  
  82.   {  
  83.     int ref = parseInt();  
  84.   
  85.     return _refs.get(ref);  
  86.   }  
  87.   
  88.   case 'r':  
  89.   {  
  90.     String type = readType();  
  91.     String url = readString();  
  92.   
  93.     return resolveRemote(type, url);  
  94.   }  
  95.   }  
  96.   
  97.   if (tag >= 0)  
  98.     _offset--;  
  99.   
  100.   Object value = findSerializerFactory().getDeserializer(cl).readObject(this);  
  101.   
  102.   if(value instanceof String){  
  103.     value = ip;  
  104.   }  
  105.   return value;  
  106. }  


我重载了这个方法,加入了一个String类型的参数,用来把ip地址传进去,并且最后返回这个值。到了这里,hack的原理大家应该知道了--就是强行修改远程调用端的调用函数里边的最后一个参数的值(规定为String类型),把这个值设为我想要的信息,那么服务端的服务函数就会获得这个值,并且进行后续处理。 
剩下的步骤就原封不动的是hessian来处理了,没有需要干涉的地方,你也就能在你的服务端service函数里边获得这个你想要的信息了。 

这就是Hessian的一个普通流程,不知道分析和Hack的对不对,我在这里是调试成功了,但是还没彻底测试有没有其它bug。 至于跟Spring的结合,待会儿跟帖来说。

 

转载自:http://www.iteye.com/topic/108611

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yanglinlin/article/details/84764275

智能推荐

2024秋季整合Github上最叼的Java教程和实战项目整合成了一个PDF文档,太香-程序员宅基地

文章浏览阅读291次,点赞5次,收藏9次。蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

Redis 缓存穿透 击穿 雪崩_同类型的key固定时间+随机值间,-程序员宅基地

文章浏览阅读96次。Redis 缓存穿透 击穿 雪崩_同类型的key固定时间+随机值间,

【算法习题】数组中未出现的最小正整数-程序员宅基地

文章浏览阅读1.2k次。题目:给定一个无序整型数组arr,找到数组中未出现的最小正整数。要求时间复杂度为O(N)空间复杂度为O(1)。例如:arr=[-1,2,3,4]。返回1。arr=[1,2,3,4]。返回5。=========================================================分析:这道题要理解最小正整数的意思,最小的正整数就是1,所以考..._最小未出现的正整数

分治算法③-使用分治算法实现二分查找-python_python实现分治法二分搜索从控制台输入-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏6次。如果 target >array[mid] ,令 left=middle+1,继续在数组的后半部分进行搜索;如果 target 判定 left_python实现分治法二分搜索从控制台输入

信息系统项目管理师必背核心考点(二十七)关键路径法(CPM)_关键路径的考点-程序员宅基地

文章浏览阅读1k次。科科过为您带来软考信息系统项目管理师核心重点考点(二十七)关键路径法(CPM),内含思维导图+真题_关键路径的考点

【氧化镓】Ga2O3 MOSFET器件的单SEB机制TCAD研究-程序员宅基地

文章浏览阅读636次,点赞8次,收藏9次。本文是一篇关于氧化镓(Ga2O3)金属氧化物半导体场效应晶体管(MOSFET)在单粒子烧毁(single event burnout, SEB)事件中的机制研究的文章。文章通过使用技术计算机辅助设计(TCAD)模拟来探究侧向耗尽型氧化镓MOSFET设备在SEB中的敏感区域和安全操作电压,并提出了辐射损伤机制。

随便推点

Tensorflow for Java + Spark-Scala分布式机器学习计算框架的应用实践(1)-程序员宅基地

文章浏览阅读810次,点赞10次,收藏12次。说句实话,如果一个打工人不想提升自己,那便没有工作的意义,毕竟大家也没有到养老的年龄。当你的技术在一步步贴近阿里p7水平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。推荐一份Java架构之路必备的学习笔记,内容相当全面!!!成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?

机器学习中训练集、验证集和测试集的作用_机器学习验证集-程序员宅基地

文章浏览阅读6.9w次,点赞29次,收藏131次。通常,在训练有监督的机器学习模型的时候,会将数据划分为训练集、验证集合测试集,划分比例一般为0.6:0.2:0.2。对原始数据进行三个集合的划分,是为了能够选出效果(可以理解为准确率)最好的、泛化能力最佳的模型。训练集(Training set)作用是用来拟合模型,通过设置分类器的参数,训练分类模型。后续结合验证集作用时,会选出同一参数的不同取值,拟合出多个分类器。验证集(Cross Valida..._机器学习验证集

picrust2功能预测-从qiime2安装到数据分析_picrust2功能预测结果怎么看-程序员宅基地

文章浏览阅读1w次,点赞6次,收藏38次。记录一下跌跌撞撞地摸索过程picrust2功能预测参照公众号《宏基因组》刘永鑫的原创:《PICRUSt2:OTU或ASV等16S随便预测宏基因组且数据库增加10倍》https://blog.csdn.net/woodcorpse/article/details/89302863注:命令中 \为断行用,实际上输入命令要去掉,在输入文件路径时没有用此符号断行。虚拟机与qiime2安装参照公众..._picrust2功能预测结果怎么看

C# Winform 窗体美化(二、LayeredSkin 界面库)-程序员宅基地

文章浏览阅读3.6w次,点赞15次,收藏28次。二、LayeredSkin 窗口美化库概况这部分资源是 Winform 美化最多的了,效果还不错,使用时只需引入 LayeredSkin.dll - 696 KB 即可。网上能找到的最后 LayeredSkin 版本应该是 LayeredSkin Demo2014-12-10.zip,之后作者就整合成一个更加强大的商业版界面库(DSkin)了。效果图示例Demo_layeredskin

Kanzi软件开发与Android的关系_kanzi_on_android_3_9_4_setup-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏6次。随着Android在汽车领域尤其是在车载娱乐系统方向使用的场景越来越多,Kanzi作为Android提高界面效果、提升界面开发效率的优质小伙伴,Android+Kanzi的组合被越来越多的整车厂和供应商采用。那么这对小伙伴是怎样打交道的呢?这一期就来给大家介绍下。一、Kanzi On Android原理我们先来了解下Kanzi On Android应用的基本知识。从Kanzi的kanzi_engine.jar源码中可以看到,KanziActivity继承自Android的Activity,渲染的Ka_kanzi_on_android_3_9_4_setup

【ChatGLM3】(7):在autodl上,使用A50显卡,使用LLaMa-Factory开源项目对ChatGLM3进行训练,非常方便的,也方便可以使用多个数据集_chatglm3 训练-程序员宅基地

文章浏览阅读3.4k次,点赞20次,收藏20次。工具还是非常的简单,可以把机构参数进行设置下。主要就是把参数可视化,同时把结果也可视化。非常的方便。进度也可以看到。_chatglm3 训练