Google输入法和Java不兼容

一直发现自己写的Swing界面无法关闭,症状是点击了界面的关闭按钮后程序会卡住,然后点击无响应最后就挂掉了。 最开始以为是自己的资源没释放,但是没理由呀,应该在关闭的时候会自动释放,而且改了代码也没用。 今天再执行另一个Swing的时候,eclipse报错了 # # A fatal error has been detected by the Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d986cc3, pid=700, tid=2280 # # JRE version: Java(TM) SE Runtime Environment (7.0_45-b18) (build 1.7.0_45-b18) # Java VM: Java HotSpot(TM) Client VM (24.45-b08 mixed mode, sharing windows-x86 ) # Problematic frame: # C [GOOGLEPINYIN2.IME+0x96cc3] # # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows 看问题说是Google拼音输入法冲突,导致访问禁止,在PChunder里卸载掉javaw的Google拼音模块,javaw马上就关闭了,于是修改系统的默认输入法为其他输入法问题解决。 我了个去,纠结了我好长时间。我说为啥公司电脑和我的电脑都会关不了呢…

2014-03-29 · 1 min · bystander

linux编写定时任务

linux中定时任务用来执行一些周期性的自动化的任务,比如有些人可能用来定期备份,也可能是定期检查一下特殊文件的签名,如果不一致,就报警,检测入侵。 cron是linux下的定时执行工具 这个工具的几个命令是这样的 /sbin/service crond start //启动服务 /sbin/service crond stop //关闭服务 /sbin/service crond restart //重启服务 /sbin/service crond reload //重新载入配置 注意,这几个服务都是要以root权限才能运行的,很多时候,只要我们可能只是一个低权限的用户,那么我们要执行一些定时任务的时候,可以这样做 直接通过这个命令来编辑,无需root用户 crontab 首先添加定时任务 crontab -e 打开之后按如下的格式编写 */1 * * * * ls >> /tmp/ls.txt 从左到右一次表示 分钟 一小时的第几分 0-59 小时 一天的第几小时 0-23 日期 一个月的的第几天 1-31 月份 一年的第几个月 1-12 周几 一周的第几天 0-6 /1表示每一天 /2表示每两天,直接*的话就表示每天/每小时这样 写完之后,wq保存退出 然后 crontab -l //列出当前的所有调度任务 可以看到自己的定时任务了,然后就不要做什么操作了,操作系统定时会读取配置的,编辑完成之后,我们的定时任务过一会就会生效了。 有时候,可能还要把结果信息和一些错误信息也写入 30 5 * * * ls >>/result/test 2>&1 注:2>&1 表示执行结果及错误信息。 这里就是说明天的5点50执行一次ls命令,并把结果追加到文件 如果我想每天5点30和17点30都执行一次呢,使用逗号隔开就行了 30 5,17 * * * ls >>/result/test 2>&1 如果是某个时间段呢 30 5-17 * * * ls >>/result/test 2>&1 这样5-17点钟的每个30分到会执行 如果是一些特殊的时间点,那么有更简单的方法,比如每月0点或者每天0点执行一次 @monthly ls >>/result/test 2>&1 @daily ls >>/result/test 2>&1 使用如上的关键字

2014-03-29 · 1 min · bystander

linux的CPU负载均值

当运行在Linux上的程序有问题之后,我们通常要看一下当前CPU和内存的使用情况来分析一下问题 对于CPU的使用率,通常用Load Average,也就是负载均值来度量 负载均值是啥? 负载是啥,负载就是对CPU使用率的一个计量,均值就是某一段时间内的一个平均值。 怎么看啊? 直接输入w命令 # w 20:02:51 up 23 days, 8:10, 2 users, load average: 1.20, 1.28, 1.29 第一位1.20:表示最近1分钟平均负载 第二位1.28:表示最近5分钟平均负载 第三位1.29:表示最近15分钟平均负载 或者uptime命令 $ uptime 09:50:21 up 200 days, 15:07, 1 user, load average: 0.27, 0.33, 0.37 我们一般认为0.00表示无负载,可以理解为CPU空闲,1.00表示CPU满负载,但是注意,1.00是对于单cpu来说的,也就是说,如果是双核,那么这个满负载显示的值应该是2.00,以此类推。 怎么看我是几核啊 grep 'model name' /proc/cpuinfo | wc -l 通过统计cpuinfo的model name信息来算的 这三个值哪个重要? 一分钟内突然负载很大没关系,当然如果你要排查也没人拦着,如果15分钟的负载均值超过cpu的数目,就要关注了。 那什么就是理想负载呢? 以单个cpu为例,1.00表示cpu满负载运行,没有一点点浪费,实际上,有些管理员认为0.7也许是理想的状态。如果你的经常超过0.7,那么最好查一查。

2014-03-08 · 1 min · bystander

eclipse管理多个workplace

由于eclipse用的比较多,管理多个workplace很麻烦,经常需要打开以后再切换,简单介绍个方法。 一 1.进入Eclipse的安装目录,鼠标点击eclipse.exe,右键菜单–>发送到–>桌面快捷方式 2.到桌面上找到“eclipse.exe - 快捷方式”,鼠标右键点击查看属性,弹出菜单中选择“快捷方式”标签,然后在“目标”中增加内容:-data e:\workspace,保存后即可 3.双击这个快捷方式,eclipse就会使用e:\workspace作为工作空间启动。 这样你多复制几个,就好了。 二 1.找个目录,新建一个文件夹,名称为workspace_aaa 2.然后在当前目录下新建一个txt文件 3.输入内容为: start E:\eclipse\eclipse.exe -data workspace1 说明:前面是eclipse的路径,中间加上"-data” ,后面为工作空间的路径,start要有,不然打开eclipse之后,命令行窗口不会自动消失的,很是碍眼。 4.将这个txt保存为workspace1.bat 5.双击这个workspace1.bat,eclipse就会使用workspace1.bat 作为工作空间启动。 对launchy党来说,新建个目录,然后创建好多个bat,以后直接快速启动真是太方便了

2014-03-08 · 1 min · bystander

[译]使用Mockito简单mock入门

我们在写单元测试的时候,面临的一个挑战就是要测试的内容总是依赖于其他组件,要是我们还得先配置好其他组件,未免有点不如意,那么我们可以使用Mocks来代替那些依赖的组件 本文问了展示这个过程,我会创建一个DAL,数据访问层,这是一个类,提供了一个通用的api来访问和修改数据仓库的数据,然后,我们要测试这个api,而不用配置连接某个本地的数据库,,或者一个远程的数据库,或者是一个文件系统,反正就是任何放数据的东西,DAL层的好处就是隔离开了数据访问和应用程序代码 首先使用maven来创建一个工程 mvn archetype:generate -DgroupId=info.sanaulla -DartifactId=MockitoDemo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 执行之后,本地生成MockitoDemo 文件夹,然后整个工程的目录结构与生成好了。 然后,我们写这样一个model类,表示book类型 package info.sanaulla.models; import java.util.List; /** * Model class for the book details. */ public class Book { private String isbn; private String title; private List<String> authors; private String publication; private Integer yearOfPublication; private Integer numberOfPages; private String image; public Book(String isbn, String title, List<String> authors, String publication, Integer yearOfPublication, Integer numberOfPages, String image){ this.isbn = isbn; this.title: = title; this.authors = authors; this.publication = publication; this.yearOfPublication = yearOfPublication; this.numberOfPages = numberOfPages; this.image = image; } public String getIsbn() { return isbn; } public String getTitle() { return title; } public List<String> getAuthors() { return authors; } public String getPublication() { return publication; } public Integer getYearOfPublication() { return yearOfPublication; } public Integer getNumberOfPages() { return numberOfPages; } public String getImage() { return image; } } 然后,我们访问Book model的DAL类会如下 package info.sanaulla.dal; import info.sanaulla.models.Book; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * API layer for persisting and retrieving the Book objects. */ public class BookDAL { private static BookDAL bookDAL = new BookDAL(); public List<Book> getAllBooks(){ return Collections.EMPTY_LIST; } public Book getBook(String isbn){ return null; } public String addBook(Book book){ return book.getIsbn(); } public String updateBook(Book book){ return book.getIsbn(); } public static BookDAL getInstance(){ return bookDAL; } } DAL层现在还没啥功能,我们要通过TDD来测试,实际中,DAL可能和ORM来交互,也可能和数据库API交互,但是我们设计DAL的时候,不用关心 ...

2014-03-01 · 3 min · bystander

尝试JavaFX开发

曾经有报道说JavaFX将使java在桌面开发上大有作为,感觉好像是很高端的样子,今天尝试了一下,界面对于自用的工具来说,本来也不多重要,只是一个简单的尝试 简单说下大致的步骤和一些思路,可能有错误。 javafx需要sdk支持,java7之后的都有的。设计思路是数据和代码分离,界面通过xml或json数据来描述,这样就把业务逻辑代码和界面实现代码分开了 一个简单的开发过程应该是这样的 1.使用JavaFX Scene Builder来绘制界面,保存为xml/json格式 画的话没啥要说的,了解一下基本的整体概念就行。 2.在eclipse里新建工程,可以是普通工程,将1中的文件放到资源目录,在代码里加载,然后界面就加载成功了。 Node topNode = FXMLLoader.load(AFI.class.getResource("/afimain.fxml")); 逻辑代码,比如一个简单的按钮事件可以通过 Node node = topNode.lookup("#paneRightBottom"); 来查找到id为paneRightBottom的元素,然后就可以通过对node添加事件监听器来完成一些功能了 主要想说的是: JavaFX和WPF其实思路是一模一样的,恰好WPF我也用过,感觉两个都没搞起来,虽然界面炫,然后我去维基看了下: 该产品于2007年5月在JavaOne大会上首次对外公布。JavaFX技术主要应用于创建Rich Internet application(RIAs)。JavaFX期望能够在桌面应用的开发领域与Adobe公司的AIR、OpenLaszlo以及微软公司的Silverlight相竞争 已经7年了,用户数应该是非常少的,成熟的商业型产品也没几个,在尝试的过程中,我在stackoverflow,以及一些很不错的java博客上,大量查找基本也没有太多的信息,都是一些很浅的应用,包括stackoverflow上的回答数,基本还是能反映出来的,主要应用于RIA,而当前RIA已经出html5的天下了。SL早都不更新了,这种坑爹的所谓新技术。 Oracle还是好好把Swing搞好吧。。不建议尝试。

2014-02-11 · 1 min · bystander

[笔记]写代码遇到的一些问题汇总下

本篇是用来填上一篇 挖下的坑的。 1.java调用webservice 有一些已有的webservice服务,由xfire生成发布,有些有参数,有些无参数,无参数的直接我直接使用org.codehaus.xfire这个包里的Client来动态生成客户端。然后调用就可以了。非常简单 Client client = null; try { client = new Client( new URL( "http://leaver.me/testService?wsdl")); client.invoke("refreshAllCache", new Object[0]); } catch (MalformedURLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } 但对于有参的,且是服务器自定义的类作为参数的时候,实在是搞不定。。不管是把自定义的类放到本地,包名一致,在invoke的时候生成这个对象还是其他什么方法。都无法完成。 最终换了直接发送soap报文来完成。dirty hack啊。如果你有一些好的方法希望不吝赐教。 解决方案来源自stackoverflow,因为stackoverflow现在国内好像有时候打不开。因此把代码贴过来。有疑问的话留言讨论。 import javax.xml.soap.*; import javax.xml.transform.*; import javax.xml.transform.stream.*; public class SOAPClientSAAJ { /** * Starting point for the SAAJ - SOAP Client Testing */ public static void main(String args[]) { try { // Create SOAP Connection SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance(); SOAPConnection soapConnection = soapConnectionFactory.createConnection(); // Send SOAP Message to SOAP Server String url = "http://ws.cdyne.com/emailverify/Emailvernotestemail.asmx"; SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url); // Process the SOAP Response printSOAPResponse(soapResponse); soapConnection.close(); } catch (Exception e) { System.err.println("Error occurred while sending SOAP Request to Server"); e.printStackTrace(); } } private static SOAPMessage createSOAPRequest() throws Exception { MessageFactory messageFactory = MessageFactory.newInstance(); SOAPMessage soapMessage = messageFactory.createMessage(); SOAPPart soapPart = soapMessage.getSOAPPart(); String serverURI = "http://ws.cdyne.com/"; // SOAP Envelope SOAPEnvelope envelope = soapPart.getEnvelope(); envelope.addNamespaceDeclaration("example", serverURI); /* Constructed SOAP Request Message: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:example="http://ws.cdyne.com/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <example:VerifyEmail> <example:email>[email protected]</example:email> <example:LicenseKey>123</example:LicenseKey> </example:VerifyEmail> </SOAP-ENV:Body> </SOAP-ENV:Envelope> */ // SOAP Body SOAPBody soapBody = envelope.getBody(); SOAPElement soapBodyElem = soapBody.addChildElement("VerifyEmail", "example"); SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("email", "example"); soapBodyElem1.addTextNode("[email protected]"); SOAPElement soapBodyElem2 = soapBodyElem.addChildElement("LicenseKey", "example"); soapBodyElem2.addTextNode("123"); MimeHeaders headers = soapMessage.getMimeHeaders(); headers.addHeader("SOAPAction", serverURI + "VerifyEmail"); soapMessage.saveChanges(); /* Print the request message */ System.out.print("Request SOAP Message = "); soapMessage.writeTo(System.out); System.out.println(); return soapMessage; } /** * Method used to print the SOAP Response */ private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); Source sourceContent = soapResponse.getSOAPPart().getContent(); System.out.print("\nResponse SOAP Message = "); StreamResult result = new StreamResult(System.out); transformer.transform(sourceContent, result); } } 2.Access restriction on class due to restriction on required library rt.jar? 报错 ...

2014-02-08 · 4 min · bystander

[藏]跨行清算系统的实现原理

本文来自God Is Coder,通过这篇文章我算是理解了跨行清算系统逻辑,非常非常好。 最近看了很多银联方面的清算系统的设计原理,对于跨行清算系统有了很大的了解,写这篇文章的目的是在于从一个程序员的角度去思考一个跨行清算系统的架构是如何实现的以及整个过程中我们有哪些思想是可以借鉴的。由于金融里面涉及到太多的专业名词,包括借贷,备付金,头寸,调拨等等,这里不会涉及到这些,取而代之的是以大家可以理解的概念去解释。 下面简单的介绍一下两种跨行清算系统的实现原理以及特点。一种跨清算系统是我们最熟悉的银联,还有一种是越来越流行的第三方支付系统,比较典型的是快钱。 首先来拿生活中的一个非常常见的例子来说明跨行清算的整个过程,这里面不涉及交易费等其他概念。 跨行取款流程 张三是工行的持卡人,他需要取现金,但是找不到工行的ATM机器,发现附近有建行的ATM机器,他只能去建行取款,整个过程就是跨行清算的过程,我们以这个场景为例,分析一下业务流程,具体交互流程见下面一张图。 工行持卡人张三在建行ATM机器取款100,ATM请求建行主机,由于是工行的卡,建行不识别,只能请求工行去处理,工行识别持卡人账户并扣款100,然后通知建行,建行则通知atm吐钱。 这里整个系统要解决两个问题: 1 建行如何与工行通信 2 建行和工行之间如何清算,如上图结果,工行欠建行100. 整个系统的分析基于以上两个问题,下面首先解决是通信问题 跨行通信的两种模式 我们先假设工行提供接口,只需要建行发送指约定格式的报文,即可于工行通信,这种相当于建行直接通过接口方式与工行通信。如果是这种方式,只能解决建行和工行的单向通信,如果工行和建行通信,则工行要发送建行指定的通信报文格式。可是大家想想,如果银行更多怎么办,下面是三家银行间的通信 当有三家银行的时候,通信链路就有3*2=6条,当银行越来越多的时候,这种点对点的通信变的越来越复杂,每新增一家银行,他要做之前银行都要做的很多重复性的劳动,这样的成本非常高,也不经济,那么必须出现一个网络,它能够接入所有的银行,新的银行只需要接入这个网络,就可以和其他所有的银行进行通信。 先把这个网络成为通信网络,这种通信网络有两种方式可以连接所有的银行 1 这个通信网络定义标准接口,所有的银行都必须实现这个通信网络定义的api,新的银行如果想要接入这个通信网络,必须实现通信接口约定的协议。简称公共接口模式 2 这个通信网络主动去连接所有的银行的接口,把所有银行的接口信息都接入里面,就像一个适配器,新的银行如果想要接入这个通信网络,这个通信网络必须主动联系银行,按照银行的接口协议实现通信,简称适配器模式。 下面一幅图演示了这两种模式的不同: 对于这两模式,主要博弈就在于谁强谁弱。显然第三方支付公司属于适配器模式,需要一家一家银行去接入,至于银联,个人认为应该是第一种模式,这种对于银联这种需要稳定的系统来说是最具有优势的。 跨行清算保证金模式 解决了通信问题,下面就看如何解决资金的清算问题。一种简单的方案就是工行在建行里面开设一个保证金账户,用这个账户去偿还在整个跨行交易中应付给建行的资金。 从上图来看,这种方案确实可行。只需要工行在建行里面放足额的保证金,就可以满足跨行的费用。但是这里面实际上存在非常多的问题, 1 如果银行越来也多,每个银行都要在其他银行存钱,太不经济了 2 保证金需要放多少资金?如果一直都没有发生跨行交易,工行就亏大发了 3 如果保证金不够怎么办?交易失败还是记应收款? 对于第一个问题假设银行越来越多,会导致工行需要在其他每个银行里面都开设保证金账户(见下图),是一个很不经济的方案。 说明这个在其他银行存保证金的方案是不可行的,和之前通信的问题一样,是不是可以把所有的银行保证金账户单独管理起来,统一放置在一起,方便各个银行之间的清算。我们暂时把这个系统称之为保证金系统。 保证金系统 保证金就是方便各个银行之间的清算,需要单独由一个系统进行管理,解决了跨行之间保证金存放的问题。每个银行只需要在保证金系统中存点钱就可以了。保证金系统也有两种模式。先看看比较好理解的第一种模式: 在这种模式下,银行先把一部分钱存放在保证金系统里面,同时银行内部建立一个虚拟账户,记录存放了多少钱,主要是方便对账,万一这个保证金系统钱算错了怎么办。你可以想象一下,银行是很小气的,为啥愿意把钱存放到这保证金系统里面,这部分钱干啥不好,能够银行这么干的只有国家了,这个系统就是央行的备付金管理系统。每个新增的银行都要存一份钱在这里。 另外一种方案是倒过来思考,既然没有牛逼的央行作支撑,那可以在每个商业银行都建立一个账户,用这个账户负责和银行进行清算。每新增一家银行,就在那个银行里面开一个保证金账户。 这两种方式有本质的不同,一个是银行把资金的一部分转出到保证金,银行建立虚拟账户和保证金里面真实的资金映射。一个是保证金系统把资金转出到各个银行,自己内部建立一个虚拟账户和银行中真实的资金账户进行映射。这个间接的银行了后续的对账机制,这里先不叙述。 所有的第三方支付公司跨行清算的流程都是第二种方式,只有国家级清算公司(比如银联)是第一种方式,这是一种资源和权力上的不平等,不过是可以理解的。 清算系统 保证金系统解决了保证金存放的问题,接下来就是解决如何清算的问题。假设保证金转账是实时的,就要面对上面说的问题,保证金不够的情况下,跨行交易是成功还是失败。这是一个业务上问题,有很多种解决方案,我们暂不说。从技术上来讲,如果每一笔交易都要保证金实时记账,那么保证金系统的负载太大,事务如何保证等等一些列的问题。所以一个最简单的方案就是:一天结算一次。 每天由一个系统记录这些跨行交易信息,汇总出来,统一记账。这样一天只需要调用一次保证金系统即可。那么整个清算过程则是下面的流程: 1 系统T日发生建行和工行的跨行交易100 2 清算系统T+1日汇总T日工行和建行之间发生的交易明细数据,并且发这些数据发给建行和工行进行确认 3 工行建行分别对明细对账确认之后,通知清算系统确认交易明细无误,清算系统开始清算,调用保证金支付系统转账。 4 清算完成之后,工行和建行分别获取保证金系统的真实金额和自身系统内部的映射账户进行余额对账。 清算中心最主要干得事情就是统计谁欠谁多少钱,以及触发保证金系统的调拨操作。 对账流程 对账包括两个部分,一个是跨行交易明细的对账以及保证金余额的对账。 首先要思考的是:对账是谁发起的 ? 这个是了解对账的本质。 我们举生活中的一个例子,我们把钱投资到一个人,那个人负责公司的日常运作。你肯定会主动了解公司的账务,因为那个是你的钱。对账的发起人也是如此,对于银联的清算过程,对账的发起者是商业银行,因为你把钱放在保证金系统里面,这是你的钱,你需要去关心这个的,银联可不关心这个。 对于另外一种保证金系统,把钱放在各个银行里面了,那么对账的发起者就是这个保证金系统维护者了。目前普遍的第三方支付公司都是这个模式,所以他要找各个银行要结果明细进行对账,确认自己的资金安全无误。 以上就是一个简单的跨行清算系统的雏形,从一个就简单的例子入手,说明一个清算过程。目前银联的第三方支付公司的清算过程大致如此,但是实现细节远比这个复杂。但是一个基本的清算系统的本质模型大体上是不会变的。当然这个只是对于同币种的清算,不同币种或者虚拟货币的清算会涉及到汇率的问题,这些就很复杂,有机会在研究一下,后续在分享。 PS:以上很多名词都是自己的随意写的,里面很多专业名词这里不提及,有兴趣的可以自己去了解。

2013-12-14 · 1 min · bystander

[藏]Class.getResource和ClassLoader.getResource不同点

有一次遇到了,查了查。原文地址 Java中取资源时,经常用到Class.getResource和ClassLoader.getResource,这里来看看他们在取资源文件时候的路径问题。 Class.getResource(String path) path不以’/'开头时,默认是从此类所在的包下取资源; path 以’/'开头时,则是从ClassPath根下获取; 什么意思呢?看下面这段代码的输出结果就明白了: package testpackage; public class TestMain { public static void main(String[] args) { System.out.println(TestMain.class.getResource("")); System.out.println(TestMain.class.getResource("/")); } } 输出结果: file:/E:/workspace/Test/bin/testpackage/ file:/E:/workspace/Test/bin/ 上面说到的【path以’/'开头时,则是从ClassPath根下获取;】在这里就是相当于bin目录(Eclipse环境下)。 再来一个实例,假设有如下Project结构: 如果我们想在TestMain.java中分别取到1~3.properties文件,该怎么写路径呢?代码如下: package testpackage; public class TestMain { public static void main(String[] args) { // 当前类(class)所在的包目录 System.out.println(TestMain.class.getResource("")); // class path根目录 System.out.println(TestMain.class.getResource("/")); // TestMain.class在<bin>/testpackage包中 // 2.properties 在<bin>/testpackage包中 System.out.println(TestMain.class.getResource("2.properties")); // TestMain.class在<bin>/testpackage包中 // 3.properties 在<bin>/testpackage.subpackage包中 System.out.println(TestMain.class.getResource("subpackage/3.properties")); // TestMain.class在<bin>/testpackage包中 // 1.properties 在bin目录(class根目录) System.out.println(TestMain.class.getResource("/1.properties")); } } ※Class.getResource和Class.getResourceAsStream在使用时,路径选择上是一样的。 Class.getClassLoader().getResource(String path) path不能以’/'开头时; path是从ClassPath根下获取; 还是先看一下下面这段代码的输出: package testpackage; public class TestMain { public static void main(String[] args) { TestMain t = new TestMain(); System.out.println(t.getClass()); System.out.println(t.getClass().getClassLoader()); System.out.println(t.getClass().getClassLoader().getResource("")); System.out.println(t.getClass().getClassLoader().getResource("/"));//null } } 输出结果: class testpackage.TestMain sun.misc.Launcher$AppClassLoader@1fb8ee3 file:/E:/workspace/Test/bin/ null 从结果来看【TestMain.class.getResource("/") == t.getClass().getClassLoader().getResource("")】 如果有同样的Project结构 使用Class.getClassLoader().getResource(String path)可以这么写: package testpackage; public class TestMain { public static void main(String[] args) { TestMain t = new TestMain(); System.out.println(t.getClass().getClassLoader().getResource("")); System.out.println(t.getClass().getClassLoader().getResource("1.properties")); System.out.println(t.getClass().getClassLoader().getResource("testpackage/2.properties")); System.out.println(t.getClass().getClassLoader().getResource("testpackage/subpackage/3.properties")); } }   ※Class.getClassLoader().getResource和Class.getClassLoader().getResourceAsStream在使用时,路径选择上也是一样的。

2013-12-14 · 1 min · bystander

Java动态代理实例

首先什么是代理? 所谓代理呢也就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。 那动态代理呢,官方解释是: Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。 老湿,你说的是个毛啊,完全没看懂啊! 我更喜欢另一种通俗的解释,官方的解释总是高度抽象的,等用了一段时间才能理解体会 动态代理实现了日志和业务的分开,也就是某个类只是要提供了某些业务,比如银行取款业务。这个类实现了取款业务的同时也需要实现日志功能,如果不用动态代理的话,那么由此一来该类代码里面已经额外地添加了自己不该添加的日志功能能代码。所以我们就得使用动态代理把它的业务代码和日志功能代码分开。所以用到了动态代理概念,spring里面的AOP就是一个很好的例子。 不直观啊,老湿,能再给力一点不? 额,这样的话,我们来看一个例子,要用到的两个类 实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,也就是真正做事的,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行业务方法,在业务方法被调用的同时,执行处理器会被自动调用。 记住,动态代理只能对接口 首先业务接口: public interface HelloWorld { public void sayHelloWorld(); } 然后我们是这样写的实现 public class HelloWorldImpl implements HelloWorld { public void sayHelloWorld() { System.out.println("Hello World!"); } } 后来我们觉得执行这个方法前能不能做点其他啥事呢,比如写个日志?见个妹子?啥,这段代码不让改了,改了的话,业务方法和日志混合的一塌糊涂啊,以后想改个日志格式你来写啊 那我们就得定义一个拦截器/执行处理器了。 public class HelloWorldHandler implements InvocationHandler { //目标对象 private Object targetObject; public HelloWorldHandler(Object targetObject){ this.targetObject = targetObject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法调用前"); Object result = method.invoke(this.targetObject, args); System.out.println("方法调用结束"); return result; } } 这客户端咋用啊,老湿 public class HelloWorldTest { public static void main(String[] args) { //业务对象 HelloWorld obj = new HelloWorldImpl(); //拦截器对象 HelloWorldHandler handler = new HelloWorldHandler(obj); //返回业务对象的代理对象 HelloWorld proxy = (HelloWorld)Proxy.newProxyInstance( obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); //通过代理对象执行业务对象的方法 proxy.sayHelloWorld(); } } 看到没,通过Proxy类的newProxyInstance方法,传入类加载器,类接口,和这个处理器,我们就获得一个代理 执行结果是这样的 方法调用前 Hello World! 方法调用结束 恩,电脑没死机,是这样的

2013-11-24 · 1 min · bystander