Java 正则表达式分组与捕获

JAVA 正则表达式 分组与捕获 import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Fenzhu { public static void main(String[] args) { Pattern p = Pattern.compile("(/d{3,5})([a-z]{2})"); String s = "123aa-34345bb-234cc-00"; Matcher m = p.matcher(s); while(m.find()) { System.out.println("m.group():"+m.group()); //打印所有 System.out.println("m.group(1):"+m.group(1)); //打印数字的 System.out.println("m.group(2):"+m.group(2)); //打印字母的 System.out.println(); } System.out.println("捕获个数:groupCount()="+m.groupCount()); } } 1 概述 1.1 什么是捕获组 捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用。当然,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部。 捕获组有两种形式,一种是普通捕获组,另一种是命名捕获组,通常所说的捕获组指的是普通捕获组。语法如下: 普通捕获组: (Expression) 命名捕获组: (?<name>Expression) ...

Created 19196-08-19 · Updated 9096-10-09 · 4 min · 642 words · -

Java 线程池, thread pool, Executors, ThreadPoolExecutor

Java 线程池, thread pool, Executors, ThreadPoolExecutor Executors ThreadPoolExecutor ExecutorService 在 Java 1.5 引入 ExecutorService 之后,基本上已经不建议直接创建 Thread 对象,而是统一使用 ExecutorService。毕竟从接口的易用程度上来说 ExecutorService 就远胜于原始的 Thread,更不用提 java.util.concurrent 提供的数种线程池,Future 类,Lock 类等各种便利工具。 在操作系统中,线程是一个非常重要的资源,频繁创建和销毁线程会降低系统性能。Java 线程池原理类似于数据库连接池,目的就是帮助我们实现线程复用,减少频繁创建和销毁线程。ThreadPoolExecutor Executors Executors 提供了一些创建线程池的工具方法。 ExecutorService es = Executors.newSingleThreadExecutor() 源码实现: new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) corePoolSize 和maximumPoolSize都为1,也就是创建了一个固定大小是1的线程池,workQueue是 new LinkedBlockingQueue<Runnable>() 也就是队列的大小是Integer.MAX_VALUE,可以认为是队列的大小不限制。 由此可以得出通过该方法创建的线程池,每次只能同时运行一个线程,当有多个任务同时提交时,那也要一个一个排队执行。 Executors.newFixedThreadPool(int nThreads) 源码实现: new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) 类似Executors.newSingleThreadExecutor()也是创建了一个固定大小的线程池,但是可以指定同时运行的线程数量为nThreads。 Executors.newCachedThreadPool() 源码实现: new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()) corePoolSize为0,maximumPoolSize为Integer.MAX_VALUE可以视为无穷大,workQueue是一个SynchronousQueue。SynchronousQueue可以认为是一个长度限制为0的队列,也就是向这个队列添加任务会永远是已满的状态。 由此可以得出通过该方法创建的线程池并不限制线程数量,每次添加的任务都会直接执行而不会放入workQueue,它的主要提供的功能是线程复用,但不能控制线程数量。 ...

Created 26266-08-26 · Updated 9096-10-09 · 4 min · 721 words · -

ArrayBlockingQueue

ArrayBlockingQueue ArrayBlockingQueue 是一个基于数组的阻塞队列实现,此队列按 FIFO (先进先出) 原则对元素进行排序, 在 ArrayBlockingQueue 内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。 ArrayBlockingQueue 在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于 LinkedBlockingQueue, 按照实现原理来分析 ArrayBlockingQueue 完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。Doug Lea 之所以没这样去做,也许是因为 ArrayBlockingQueue 的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜。 ArrayBlockingQueue 和 LinkedBlockingQueue 间还有一个明显的不同之处在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,而后者则会生成一个额外的 Node 对象。这在长时间内需要高效并发地处理大批量数据的系统中,其对于 GC 的影响还是存在一定的区别。而在创建 ArrayBlockingQueue 时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁。 队列的头部是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。 这是一个典型的 “有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。 此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了"不平衡性"。 ArrayBlockingQueue 在构造时需要指定容量,并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理 (其实就是通过将 ReentrantLock 设置为 true 来达到这种公平性的: 即等待时间最长的线程会先操作) 。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队列,此队列按 FIFO (先进先出) 原则对元素进行排序。 PriorityBlockingQueue PriorityBlockingQueue 是一个带优先级的队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限 (看了一下源码,PriorityBlockingQueue 是对 PriorityQueue 的再次包装,是基于堆数据结构的,而 PriorityQueue 是没有容量限制的,与ArrayList一样,所以在优先阻塞队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError) ,但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元素要具有比较能力。 最后,DelayQueue (基于PriorityQueue来实现的) 是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口: ...

Created 26266-08-26 · Updated 9096-10-09 · 2 min · 386 words · -

Spring 中 bean 的作用域

Spring中bean的作用域 http://blog.csdn.net/ProvidenceZY/article/details/1878582 如何使用spring的作用域: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。 在spring2.0之前bean只有2种作用域即: singleton(单例)、non-singleton (也称prototype) , Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。 1、singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存 (singleton cache) 中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/> 或者 <bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/> 2、prototype prototype作用域部署的bean,每一次请求 (将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。 (让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。) 配置实例: <bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/> 或者 <beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/> 3、request request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例: request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置: 如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可: <web-app> ... <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> ... </web-app> 如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现: <web-app> .. <filter> <filter-name>requestContextFilter</filter-name> <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> </filter> <filter-mapping> <filter-name>requestContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ... </web-app> 接着既可以配置bean的作用域了: <bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/> 4、session session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例: 配置实例: ...

Created 16166-09-16 · Updated 9096-10-09 · 2 min · 218 words · -

Java Thread/线程

Java Thread/线程 java的线程是映射到操作系统原生线程之上的 java线程阻塞的代价 java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入,需要在户态与核心态之间切换,这种切换会消耗大量的系统资源,因为用户态与内核态都有各自专用的内存空间,专用的寄存器等,用户态切换至内核态需要传递给许多变量、参数给内核,内核也需要保护好用户态在切换时的一些寄存器值、变量等,以便内核态调用结束后切换回用户态继续工作。 如果线程状态切换是一个高频操作时,这将会消耗很多CPU处理时间; 如果对于那些需要同步的简单的代码块,获取锁挂起操作消耗的时间比用户代码执行的时间还要长,这种同步策略显然非常糟糕的。 线程状态 线程共包括以下5种状态。 新建状态 (New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。 就绪状态(Runnable): 也被称为 “可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种: 等待阻塞 – 通过调用线程的 wait() 方法,让线程等待某工作的完成。 同步阻塞 – 线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。 其他阻塞 – 通过调用线程的 sleep() 或 join() 或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。 这 5 种状态涉及到的内容包括 Object 类, Thread 类, 和 synchronized 关键字。 这些内容我们会在后面的章节中逐个进行学习。 Object 类,定义了 wait(), notify(), notifyAll( ) 等休眠/唤醒函数。 Thread 类,定义了一些列的线程操作函数。例如,sleep() 休眠函数, interrupt() 中断函数, getName() 获取线程名称等。 synchronized,是关键字;它区分为 synchronized 代码块和 synchronized 方法。 synchronized 的作用是让线程获取对象的同步锁。 在后面详细介绍 wait(), notify() 等方法时,我们会分析为什么 “wait(), notify() 等方法要定义在 Object 类,而不是 Thread 类中” ...

Created 22226-09-22 · Updated 9096-10-09 · 5 min · 866 words · -

Linux 下用 adb 为 Android 手机批量安装软件

linux下用adb为android手机批量安装软件 通常大家安装软件都是从Andorid Market或者从网上下载到手机本地安装,这有两个问题,第一个情况碰到网速慢,那要急死,第二种情况是安装的太慢,如果软件多的话,手指累死,那么,就用adb安装吧,看我的操作情况: 首先把以前安装的软件备份到电脑,比如~/backup/,接着,打开电脑上的终端,取得root权限, cd adb ./adb start-server 打开另一个终端,默认用户权限 $ cd adb $ sh install.sh (-sh里面的内容如这样: ./adb install ~/backup/***.apk……,把你要装的软件都这样编辑,一行一个软件) ok,等着吧,安装完,切换到第一个终端,执行 ./adb kill-server 安全移除手机,看看手机上是不是已经显示你安装的软件了,呵呵 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 adb-batch-install.md;title 改为「Linux 下用 adb 为 Android 手机批量安装软件」;url 改为 adb-batch-install;旧 url 加入 aliases 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 24246-09-24 · Updated 9096-10-09 · 1 min · 51 words · -

Abstract Factory with Reflection 持续改进,抽象工厂也反射

持续改进,抽象工厂也反射 http://www.cnblogs.com/shenfx318/archive/2007/01/16/621237.html 在我的上一篇文章(疑惑?改良?从简单工厂到工厂方法)中,详细论述了创建模式中简单工厂到工厂方法的演变过程,并试图结合工厂方法的设计以及.net中的反射机制之所长,改良出一种新型的工厂—反射工厂,这当然不是我的首创,经典的PetShop 中便有此工厂的身影。本文尝试按照前篇文章的思路,借着工厂方法到抽象工厂的演变过程而继续对抽象工厂进行改良,文章中的思想仅代表了作者当时的观点,有欠妥的地方,还请各位不吝赐教。 工厂模式 前面的文章提到了简单工厂和工厂方法其实是一码事,他们完成了将客户对产品功能的使用与创建具体产品职责的分割,不同的只不过是他们实现方式上的差异,工厂方法利用更加优雅的多态性取代了相对ugly的switch case…语句,从而很好的体现了设计原则中的OCP原则,此文章将不再强调这种实现上的差异性,而更多的强调两者之间设计思路上的共性,并将这种共性统称成为工厂模式,从而进一步与抽象工厂进行对比。 工厂的使用,选择的过程 工厂模式的使用,实际上是客户 (产品的消费者) 对于产品选择的过程,对于实现了相同功能的产品来讲,客户更加关心的是产品间的差异性,而工厂的作用则是将产品的生产过程封装,根据客户的要求直接返回客户需要的产品。注意,工厂只是隐藏了产品的生产过程,但是并没有剥夺客户选择的权利,那么客户的这个选择过程又是如何体现的呢?在简单工厂中,客户通过参数的形式告诉工厂需要什么样的产品,而在工厂方法中,客户通过对工厂的选择代替了直接对产品的选择,注意到工厂方法中一个工厂只有一个Create方法,也就是说一个工厂只负责生产一种产品,那么你选择了相应的工厂也就等同于你选择了对应的产品。就连改良后的反射工厂也没有消去对产品的选择,只不过是将这种选择外化 (外化到配置文件中,从而使得对代码的改动最小) 。可以说,正是由于产品间的差异性带给了客户选择的权利,这种权利是不应当被工厂取代的,那么工厂模式的价值又在哪里呢?答案是抽象与封装,工厂模式将由于客户的不同选择而可能导致的对已知事物的影响降到最低,途径是通过抽象产品取代具体产品,使得客户依赖于抽象 (越抽象的东西越稳定) ,同时将客户的选择封装到一处,隔离与具体产品间的依赖。 工厂模式与抽象工厂 前面说了这么多无关的,为得是做好铺垫,更加有益于对下文的理解,OK,终于该说说从工厂模式到抽象工厂的转变了,先来对比两张类图: 工厂方法(Factory Method) ![](http://images.cnblogs.com/cnblogs_com/shenfx318/FactoryMethod3.jpg) 抽象工厂(Abstract Factory) 从图中我们能够看到哪些差异? 最明显的一点就是在工厂方法的类关系图中只有一类产品,他们实现了一个统一的接口,而抽象工厂有多个类别的产品,他们分别实现了不同的功能 (多个接口) 。其次的一点差别就是工厂本身所具有的方法数量不同,这点差异其实也是由第一点所导致的,工厂需要有生产不同类别产品的功能,如果抽象工厂中的产品的功能简化到一个,也便成为了工厂方法。 引出类别的概念,类别是指具有相同功能的一类产品的总称。 再来看选择的过程,在工厂方法中,客户关心的只不过是实现同一样功能的不同产品间的差异,这是一个一维选择的过程。 1 IFactory factory = new FactoryA(); //选择了工厂即选择了产品 2 IProduct productA = factory.Create(); //工厂只有一个Create方法,只能生产一种产品 而在抽象工厂中,客户首先要考虑的是需要哪一样功能,其次要考虑才是产品间的差异。也就是说这是一个二维选择的过程。 1 IFactory factory = new FactoryA(); //选择了某个具体工厂 2 IProduct productA = factory.CreateProductA(); //工厂具有多个Create方法,这里选择了其中的一个 由于产品类别的增加而导致客户在考虑产品间差异的同时还要考虑产品间功能的差异,这种二维选择的过程才是工厂方法与抽象工厂之间的本质区别。 举个肯德基与麦当劳的例子,假设原来只有一家快餐店叫做麦当劳,提供的食物 (具体产品) 有汉堡、可乐、薯条,它们都可以满足你吃东西 (抽象接口) 的需求,那么你想吃快餐的时候,唯一的选择就在于吃什么,是一维选择,现在又开了一家快餐店叫做肯德基,同样供应汉堡、可乐和薯条,那么现在你若打算吃快餐,除了考虑吃什么外,还要考虑去哪里吃-肯德基还是麦当劳?这便是二维的选择。通过横向与纵向的选择才能最终锁定你要的产品。 ...

Created 12126-10-12 · Updated 9096-10-09 · 1 min · 211 words · -

死锁 (Deadlocks)

死锁 (Deadlocks) deadlocks (死锁) 所谓死锁 (Deadlock): 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。 一种情形,此时执行程序中两个或多个线程发生永久堵塞 (等待) ,每个线程都在等待被其他线程占用并堵塞了的资源。例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象。 计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。 产生死锁的原因主要是: (1) 因为系统资源不足。 (2) 进程运行推进的顺序不合适。 (3) 资源分配不当等。 如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则 就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。 产生死锁的四个必要条件: (1) 互斥条件: 一个资源每次只能被一个进程使用。 (2) 请求与保持条件: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。 (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁。 死锁的解除与预防: 理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和 解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确 定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态 的情况下占用资源,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配 。因此,对资源的分配要给予合理的规划。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 deadlocks.md;url 改为 deadlocks;旧 url 加入 aliases;categories 改为 CS 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 24246-10-24 · Updated 9096-10-09 · 1 min · 64 words · lcf

Web 服务编程,REST 与 SOAP的比较

Web 服务编程,REST 与 SOAP的比较 REST 简介 在开始我们的正式讨论之前,让我们简单看一下 REST 的定义。 REST (Representational State Transfer) 是 Roy Fielding 提出的一个描述互联系统架构风格的名词。为什么称为 REST?Web 本质上由各种各样的资源组成,资源由 URI 唯一标识。浏览器 (或者任何其它类似于浏览器的应用程序) 将展示出该资源的一种表现方式,或者一种表现状态。如果用户在该页面中定向到指向其它资源的链接,则将访问该资源,并表现出它的状态。这意味着客户端应用程序随着每个资源表现状态的不同而发生状态转移,也即所谓 REST。 关于 REST 本身,本文就不再这里过多地讨论,读者可以参考 developerWorks 上其它介绍 REST 的文章。本文的重点在于通过 REST 与 SOAP Web 服务的对比,帮助读者更深刻理解 REST 架构风格的特点,优势。 应用场景介绍 (在线用户管理) 本文将借助于一个应用场景,通过基于 REST 和 SOAP Web 服务的不同实现,来对两者进行对比。该应用场景的业务逻辑会尽量保持简单且易于理解,以有助于把我们的重心放在 REST 和 SOAP Web 服务技术特质对比上。 需求描述 这是一个在线的用户管理模块,负责用户信息的创建,修改,删除,查询。用户的信息主要包括: 用户名 (唯一标志在系统中的用户) 头衔 公司 EMAIL 描述 需求用例图如下: 图 1. 需求用例图 如图 1 所示,客户端 1 (Client1) 与客户端 2 (Client2) 对于信息的存取具有不同的权限,客户端 1 可以执行所有的操作,而客户端 2 只被允许执行用户查询 (Query User) 与用户列表查询 (Query User List) 。关于这一点,我们在对 REST Web 服务与 SOAP Web 服务安全控制对比时会具体谈到。下面我们将分别向您介绍如何使用 REST 和 SOAP 架构实现 Web 服务。 ...

Created 7076-11-07 · Updated 9096-10-09 · 6 min · 1274 words · lcf

基于 REST 的 Web 服务基础

基于REST的Web服务基础 代表性状态传输 (Representational State Transfer,REST) 在Web领域已经得到了广泛的接受,是基于SOAP和Web服务描述语言 (Web Services Description Language,WSDL) 的Web服务的更为简单的替代方法。接口设计方面这一转变的关键证据是主流Web 2.0服务提供者 (包括Yahoo、Google和Facebook) 对REST的采用,这些提供者弃用或放弃了基于SOAP和WSDL的接口,而采用了更易于使用、面向资源的模型来公开其服务。在本文中,Alex Rodriguez将向您介绍REST的基本原理。 基础 REST定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的Web服务,包括使用不同语言编写的客户端如何通过HTTP处理和传输资源状态。如果考虑使用它的Web服务的数量,REST近年来已经成为最主要的Web服务设计模型。事实上,REST对Web的影响非常大,由于其使用相当方便,已经普遍地取代了基于SOAP和WSDL的接口设计。 REST这个概念于2000年由Roy Fielding在就读加州大学欧文分校期间在学术论文"Architectural Styles and the Design of Network-based Software Architectures"首次提出,他的论文中对使用Web服务作为分布式计算平台的一系列软件体系结构原则进行了分析,而其中提出的REST概念并没有获得现在这么多关注。多年以后的今天,REST的主要框架已经开始出现,但仍然在开发中,因为它已经被广泛接纳到各个平台中,例如通过JSR-311成为了Java? 6不可或缺的部分。 本文认为,对于今天正在吸引如此多注意力的最纯粹形式的REST Web服务,其具体实现应该遵循四个基本设计原则: ·显式地使用HTTP方法。 ·无状态。 ·公开目录结构式的URI。 ·传输XML、JavaScript Object Notation(JSON),或同时传输这两者。 下面几个部分将详述这四个原则,并提供技术原理解释,说明为什么这些原则对REST Web服务设计人员非常重要。 显式地使用HTTP方法 基于REST的Web服务的主要特征之一是以遵循RFC 2616定义的协议的方式显式使用HTTP方法。例如,HTTP GET被定义为数据产生方法,旨在由客户端应用程序用于检索资源以从Web服务器获取数据,或者执行某个查询并预期Web服务器将查找某一组匹配资源然后使用该资源进行响应。 REST要求开发人员显式地使用HTTP方法,并且使用方式与协议定义一致。这个基本REST设计原则建立了创建、读取、更新和删除 (create, read, update, and delete,CRUD) 操作与HTTP方法之间的一对一映射。根据此映射: ·若要在服务器上创建资源,应该使用POST方法。 ·若要检索某个资源,应该使用GET方法。 ·若要更改资源状态或对其进行更新,应该使用PUT方法。 ·若要删除某个资源,应该使用DELETE方法。 许多Web API中所固有的一个令人遗憾的设计缺陷在于将HTTP方法用于非预期用途。例如,HTTP GET请求中的请求URI通常标识一个特定的资源。或者,请求URI中的查询字符串包括一组参数,这些参数定义服务器用于查找一组匹配资源的搜索条件。至少,HTTP/1.1 RFC是这样描述GET方法的。但是在许多情况下,不优雅的Web API使用HTTP GET来触发服务器上的事务性操作——例如,向数据库添加记录。在这些情况下,GET请求URI属于不正确使用,或者至少不是以基于REST的方式使用。如果Web API使用GET调用远程过程,则应该类似如下: GET /adduser?name=Robert HTTP/1.1 这不是非常优雅的设计,因为上面的Web方法支持通过HTTP GET进行状态更改操作。换句话说,该HTTP GET请求具有副作用。如果处理成功,则该请求的结果是向基础数据存储区添加一个新用户——在此例中为Robert。这里的问题主要在语义上。Web服务器旨在通过检索与请求URI中的路径 (或查询条件) 匹配的资源,并在响应中返回这些资源或其表示形式,从而响应HTTP GET请求,而不是向数据库添加记录。从该协议方法的预期用途的角度看,然后再从与HTTP/1.1兼容的Web服务器的角度看,以这种方式使用GET是不一致的。 除了语义之外,GET的其他问题在于,为了触发数据库中的记录的删除、修改或添加,或者以某种方式更改服务器端状态,它请求Web缓存工具 (爬网程序) 和搜索引擎简单地通过对某个链接进行爬网处理,从而意外地做出服务器端更改。克服此常见问题的简单方法是将请求URI上的参数名称和值转移到XML标记中。这样产生的标记是要创建的实体的XML表示形式,可以在HTTP POST的正文中进行发送,此HTTP POST的请求URI是该实体的预期父实体 (请参见清单1和2) : ...

Created 8086-11-08 · Updated 9096-10-09 · 2 min · 289 words · lcf

MySQL 分页

MySQL 分页 一般MySQL最基本的分页方式: select * from content order by id desc limit 0, 10 在中小数据量的情况下,这样的SQL足够用了,唯一需要注意的问题就是确保使用了索引。随着数据量的增加,页数会越来越多,查看后几页的SQL就可能类似: select * from content order by id desc limit 10000, 10 一言以蔽之,就是越往后分页,LIMIT语句的偏移量就会越大,速度也会明显变慢。 此时,我们可以通过2种方式: 一,子查询的分页方式来提高分页效率,SQL语句如下: SELECT * FROM content WHERE id <= (SELECT id FROM content ORDER BY id desc LIMIT “.($page-1)*$pagesize.”, 1) ORDER BY id desc LIMIT $pagesize 为什么会这样呢?因为子查询是在索引上完成的,而普通的查询时在数据文件上完成的,通常来说,索引文件要比数据文件小得多,所以操作起来也会更有效率。 (via) 通过explain SQL语句发现: 子查询使用了索引! id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY content range PRIMARY PRIMARY 4 NULL 6264 Using where ...

Created 15156-11-15 · Updated 9096-10-09 · 1 min · 193 words · lcf

Lambda 表达式

Lambda 与内部类 JDK 8 之前,要把「一段逻辑」当作参数传给方法,常见写法是匿名内部类——创建一个没有名字的类,并实现目标接口。Lambda 表达式针对其中最常见的一类场景做了简化:目标类型是函数式接口(通过 SAM 判定的接口)时,可以用 (参数) -> 表达式 代替整个匿名类。 同一件事,两种写法 以 Runnable 为例: // Runnable is an interface (not a class); SAM: single abstract method void run() // Left: Runnable r1 — variable type is the interface // Right: new Runnable() { ... } — not "new interface"; defines an anonymous class // that implements Runnable and overrides run(); compiler emits EnclosingClass$1.class Runnable r1 = new Runnable() { @Override public void run() { System.out.println("hello"); } }; // JDK 8 lambda; target type is still Runnable (functional interface) // Semantically same as the anonymous class above; often compiled via invokedynamic Runnable r2 = () -> System.out.println("hello"); 以 Comparator 为例(同样是「接口 + 匿名实现类」): ...

Created 17176-11-17 · Updated 9096-10-09 · 7 min · 1345 words · -

Filter FilterChain

Filter FilterChain **[http://blog.csdn.net/zhaozheng7758/article/details/6105749](http://blog.csdn.net/zhaozheng7758/article/details/6105749)** 一、Filter的介绍及使用**** 什么是过滤器? 与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。 过滤器适用于那些地方? l 为一个web应用程序的新功能建立模型(可被添加到web应用程序中或者从web应用程序中删除而不需要重写基层应用程序代码); l 向过去的代码添加新功能。 过滤器放在容器结构的什么位置? 过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter: 用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。 Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。 Filter 有如下几个用处: l 在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 l 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。 l 在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 l 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。 Filter 有如下几个种类: l 用户授权的Filter: Filter 负责检查用户请求,根据请求过滤用户非法请求。 l 日志Filter: 详细记录某些特殊的用户请求。 l 负责解码的Filter: 包括对非标准编码的请求解码。 l 能改变XML 内容的XSLTFilter 等。 一个Filter 可负责拦截多个请求或响应:一个请求或响应也可被多个请求拦截。 创建一个Filter 只需两个步骤: (1)创建Filter 处理类: (2)在web.xml 文件中配置Filter 。 创建Filter 必须实现javax.servlet.Filter 接口,在该接口中定义了三个方法。 • void init(FilterConfig config): 用于完成Filter 的初始化。 ...

Created 18186-11-18 · Updated 9096-10-09 · 3 min · 602 words · -

String Matching Algorithms 字符串匹配算法总结

字符串匹配算法总结 KMP虽然经典,但是理解起来极其复杂,好不容易理解好了,便起码来巨麻烦! 老子就是今天图书馆在写了几个小时才勉强写了一个有bug的、效率不高的KMP,特别是计算next数组的部分。 其实,比KMP算法速度快的算法大把大把,而且理解起来更简单,为何非要抓住KMP呢?笔试出现字符串模式匹配时直接上sunday算法,既简单又高效,何乐而不为? 说实话,想到sunday算法的那个人,绝对是发散思维,绝对牛。当我在被KMP折磨的够呛的时候,我就琢磨,有没有别的好算法呢??琢磨了半天也没想出个所以然来。笨啊,脑子不够发散。 下面贴上一位兄弟写的算法总结,很简单 (建议KMP部分就不用看了,看了费脑子) 。 参见: http://hi.baidu.com/willamette/blog/item/02bd0b5599c8b4c0b645ae06.html 趁着做Presentation的功夫,顺便做一个总结 字符串匹配: -willamette 在匹配串中寻找模式串是否出现,注意和最长公共子序列相区别(LCS: Longest Common Substring) **-: ** Brute Force(BF或蛮力搜索) **算法: ** 这是世界上最简单的算法了。 首先将匹配串和模式串左对齐,然后从左向右一个一个进行比较,如果不成功则模式串向右移动一个单位。 速度最慢。 那么,怎么改进呢? 我们注意到Brute Force 算法是每次移动一个单位,一个一个单位移动显然太慢,是不是可以找到一些办法,让每次能够让模式串多移动一些位置呢? 当然是可以的。 我们也注意到,Brute Force 是很不intelligent 的,每次匹配不成功的时候,前面匹配成功的信息都被当作废物丢弃了,当然,就如现在的变废为宝一样,我们也同样可以将前面匹配成功的信息利用起来,极大地减少计算机的处理时间,节省成本。^_^ 注意,蛮力搜索算法虽然速度慢,但其很通用,文章最后会有一些更多的关于蛮力搜索的信息。 **-: KMP算法 ** 首先介绍的就是KMP 算法。 原始论文: Knuth D.E., Morris J.H., and Pratt V.R., Fast pattern matching in strings, SIAM Journal on Computing, 6(2), 323-350, 1977. 这个算法实在是太有名了,大学上的算法课程除了最笨的Brute Force 算法,然后就介绍了KMP 算法。也难怪,呵呵。谁让Knuth D.E. 这么world famous 呢,不仅拿了图灵奖,而且还写出了计算机界的Bible 《The Art of Computer Programming》( 业内人士一般简称TAOCP). 稍稍提一下,有个叫H.A.Simon 的家伙,不仅拿了Turing Award ,顺手拿了个Nobel Economics Award ,做了AI 的爸爸,还是Chicago Univ 的Politics PhD ,可谓全才。 ...

Created 27276-11-27 · Updated 9096-10-09 · 5 min · 928 words · lcf

PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurer http://callan.iteye.com/blog/161540 关于PropertyPlaceholderConfigurer与PropertyOverrideConfigurer PropertyPlaceholderConfigurer,允许在spring的配置文件中加入properties文件,可以将一些动态参数移到properties中. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:config/jdoserver.properties"/> </bean> 但是好像在属性文件定义中却不支持多个属性文件的定义,比如不能这样用config/*.properties。 经过查看源码,发现可以使用locations属性定义多个配置文件: <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/maxid.properties</value> <value>classpath:config/jdoserver.properties</value> </list> </property> </bean> 使用外部属性后如下: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.agent.driver}"/> <property name="url" value="${jdbc.agent.main.url}"/> </bean> PropertyOverrideConfigurer: 在spring所有的bean初使化以后,将bean的值强行改变 <bean id="configBean" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="location"> <value>hello.properties</value> </property> </bean> <bean id="helloBean" class="com.HelloBean"> <property name="word"> <value>Hello!</value> </property> </bean> 定义HelloBean,注入word的值为hello. 在hello.properties中 helloBean.word=Welcome! word初使为hello后,当bean全加载完,PropertyOverrideConfigurer将helloBean.word的值改成为welcome. 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 8086-12-08 · Updated 9096-10-09 · 1 min · 73 words · -

html DOCTYPE

html DOCTYPE <!DOCTYPE> 声明必须是 HTML 文档的第一行,位于 <html> 标签之前。 <!DOCTYPE> 声明不是 HTML 标签;它是指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。 在 HTML 4.01 中,<!DOCTYPE> 声明引用 DTD,因为 HTML 4.01 基于 SGML。DTD 规定了标记语言的规则,这样浏览器才能正确地呈现内容。 HTML5 不基于 SGML,所以不需要引用 DTD。 添加 <!DOCTYPE> 声明,这样浏览器才能获知文档类型。 HTML Transitional DTD Transitional DTD 可包含 W3C 所期望移入样式表的呈现属性和元素。如果您的读者使用了不支持层叠样式表 (CSS) 的浏览器以至于您不得不使用 HTML 的呈现特性时,请使用此类型: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> html5 只有一种 DOCTYPE 声明 <!DOCTYPE html> <!DOCTYPE> 声明没有结束标签。 <!DOCTYPE> 声明对大小写不敏感。 http://www.w3school.com.cn/tags/tag_doctype.asp 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 8086-12-08 · Updated 9096-10-09 · 1 min · 81 words · -

resource-ref

resource-ref resource-ref元素用于指定对外部资源的servlet引用的声明。 <!ELEMENT resource-ref (description?, res-ref-name, res-type, res-auth, res-sharing-scope?)> <!ELEMENT description (#PCDATA)> <!ELEMENT res-ref-name (#PCDATA)> <!ELEMENT res-type (#PCDATA)> <!ELEMENT res-auth (#PCDATA)> <!ELEMENT res-sharing-scope (#PCDATA)> resource-ref子元素的描述如下: ● res-ref-name是资源工厂引用名的名称。该名称是一个与java:comp/env上下文相对应的JNDI名称,并且在整个Web应用中必须是惟一的。 ● res-auth表明: servlet代码通过编程注册到资源管理器,或者是容器将代表servlet注册到资源管理器。该元素的值必须为Application或Container。 ● res-sharing-scope表明: 是否可以共享通过给定资源管理器连接工厂引用获得的连接。该元素的值必须为Shareable(默认值)或Unshareable。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 5056-01-05 · Updated 9096-10-09 · 1 min · 49 words · -

obsidian

obsidian # archlinux pacman -S obsidian https://forum-zh.obsidian.md/ flatpak install flathub md.obsidian.Obsidian flatpak run md.obsidian.Obsidian https://decoge.medium.com/how-to-install-obsidian-on-a-chromebook-53e379217adf install plugin: remotely save Obsidian> settings> community plugins> turn on community plugins> browse search remotely save and install and enable config s3 storage: setting> community plugins> remotely save Choose A Remote Service: S3 or compatible endpoint: s3.ap-southeast-1.amazonaws.com region: ap-southeast-1 ak: <check in bitwarden> sk: <check in bitwarden> bucket name: obsidian-w10n 调整页边距 解决编辑区域过窄的问题 Obsidian> settings> Editor> Readable line length: diable ...

Created 12126-01-12 · Updated 9096-10-09 · 1 min · 92 words · -

Spring Annotation @Resource

Spring Annotation @Resource Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是@Resource、@PostConstruct 以及 @PreDestroy。 @Resource @Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配 (见2) ;如果没有匹配,则回退为一个原始类型 (UserDao) 进行匹配,如果匹配则自动装配; Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。 @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。 @Resource装配顺序 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常 如果指定了name,则从上下文中查找名称 (id) 匹配的bean进行装配,找不到则抛出异常 ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 358 words · -

利用 Spring 的 JdbcTemplate 处理 BLOB、CLOB

利用spring的jdbcTemplate处理blob、clob spring定义了一个以统一的方式操作各种数据库的Lob类型数据的LobCreator(保存的时候用),同时提供了一个LobHandler为操作二进制字段和大文本字段提供统一接口访问。 举例,例子里面的t_post表中post_text字段是CLOB类型,而post_attach是BLOG类型: public class PostJdbcDao extends JdbcDaoSupport implements PostDao { private LobHandler lobHandler; private DataFieldMaxValueIncrementer incre; public LobHandler getLobHandler() { return lobHandler; } public void setLobHandler(LobHandler lobHandler) { this.lobHandler = lobHandler; } public void addPost(final Post post) { String sql = " INSERT INTO t_post(post_id,user_id,post_text,post_attach)" + " VALUES(?,?,?,?)"; getJdbcTemplate().execute( sql, new AbstractLobCreatingPreparedStatementCallback( this.lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { ps.setInt(1, incre.nextIntValue()); ps.setInt(2, post.getUserId()); lobCreator.setClobAsString(ps, 3, post.getPostText()); lobCreator.setBlobAsBytes(ps, 4, post.getPostAttach()); } }); } } 设置相对应的配置文件(Oracle 9i版本),Oracle的数据库最喜欢搞搞特别的东西啦: ...

Created 16166-01-16 · Updated 9096-10-09 · 2 min · 219 words · -