开发一个真实的 OSGi 应用程序
2012-06-26 10:19
423 查看
开发一个真实的 OSGi 应用程序
我们不能只停留在 hello world 的层面,虽然那曾经对我们很重要 ,但是现实需要我们能够使用 OSGi 写出激动人心的应用程序,它能够被客户接受,被架构师认可,被程序员肯定。好的,那我们开始吧。下面将会着重介绍一些现实的应用程序可能需要的一些 OSGi 应用场景。
发布和使用服务
由于 OSGi 框架能够方便的隐藏实现类,所以对外提供接口是很自然的事情,OSGi 框架提供了服务的注册和查询功能。好的,那么我们实际操作一下,就在 Hello world 工程的基础上进行。
我们需要进行下列的步骤:
定义一个服务接口,并且 export 出去供其它 bundle 使用;
定义一个缺省的服务实现,并且隐藏它的实现;
Bundle 启动后,需要将服务注册到 Equinox 框架;
从框架查询这个服务,并且测试可用性。
好的,为了达到上述要求,我们实际操作如下:
定义一个新的包
在上述的包中新建接口
[b]清单 2. IHello
[/b]
再新建一个新的包
在上述包中新建
清单 3. IHello 接口实现
注册服务,OSGi 框架提供了两种注册方式,都是通过
我们使用第一种注册方式,修改
清单 4. 加入注册代码
为了让我们的服务能够被其它 bundle 使用,必须在 MANIFEST.MF 中对其进行导出声明,双击 MANIFEST.MF,找到runtime > exported packages > 点击 add,如图,选择 service 包即可:
图 14. 选择导出的服务包
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image014.png)
另外新建一个类似于 hello world 的 bundle 叫:
添加 import package:在第二个 bundle 的 MANIFEST.MF 文件中,找到 dependencies > Imported packages > Add …,选择我们刚才 export 出去的 osgi.test.helloworld.service 包:
图 15. 选择刚才 export 出去的 osgi.test.helloworld.service 包
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image015.png)
查询服务:同样,OSGi 框架提供了两种查询服务的引用
这里我们使用第一种查询的方法,在
清单 5. 加入查询和测试语句
修改运行环境,因为我们增加了一个 bundle,所以说也需要在运行配置中加入对新的 bundle 的配置信息,如下图所示:
图 16. 加入对新的 bundle 的配置信息
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image016.png)
执行,得到下列结果:
图 17. 执行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image017.png)
恭喜您,成功了!
回页首
使用事件管理服务 EventAdmin
前面讲过,OSGi 规范定义了很多可用的 bundle,您尽管使用它们完成您的工作,而不必另外再发明轮子,OSGi 框架定义的事件管理服务,类似于 JMS,但是使用上比 JMS 简单。
OSGi 整个框架都离不开这个服务 ,因为框架里面全都依靠事件机制进行通信,例如 bundle 的启动、停止,框架的启动、停止,服务的注册、注销等等等等都是会发布事件给监听者,同时也在监听其它模块发来的自己关心的事件。 OSGi 框架的事件机制主要核心思想是:
用户(程序员)可以自己按照接口定义自己的事件类型
用户可以监听自己关心的事件或者所有事件
用户可以将事件同步的或者异步的提交给框架,由框架负责同步的或者异步的分发给监听者
说明:框架提供的事件服务、事件提供者、事件监听者之间的关系如下:
图 18. 事件服务、事件提供者、事件监听者之间的关系
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image018.png)
事件提供者 Publisher 可以获取 EventAdmin 服务,通过 sendEvent 同步(postEvent 异步)方式提交事件,EventAdmin 服务负责分发给相关的监听者 EventHandler,调用它们的
这里要介绍一个新的概念 Topics,其实在 JMS 里面也有用,也就是说一个事件一般都有一个主题,这样我们的事件接收者才能按照一定的主题进行过滤处理,例如只处理自己关心的主题的事件,一般情况下主题是用类似于 Java Package 的命名方式命名的。
同步提交(sendEvent)和异步提交(postEvent) 事件的区别是,同步事件提交后,等框架分发事件给所有事件接收者之后才返回给事件提交者,而异步事件则一经提交就返回了,分发在另外的线程进行处理。
下面的程序演示了事件的定义、事件的发布、事件处理,同时还演示了同步和异步处理的效果,以及运行环境的配置。
(约定
图 19. 同步和异步处理演示
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image019.png)
在 bundle1 中的 MANIFEST.MF 的 dependency 页面中定义引入新的包:
在 bundle1 中的
清单 6. 定义新的类 MyEvent
在 bundle1 的
清单 7. getHello 方法
定义监听者,在 bundle2 中,也引入 osgi 的事件包,然后定义一个新的类:
清单 8. MyEventHandler类
注册监听器,有了事件处理器,还需要注册到监听器中,这里在 bundle2 的
清单 9. start 方法
为了使用框架的事件服务,需要修改运行环境,加入两个系统 bundle,分别是:
好了一切准备好了,执行:
图 20. 执行
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image020.png)
可以看到,
图 21. ss 查询
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image021.png)
OK,修改代码以测试同步调用的情况,我们只需要把提交事件的代码由
图 22. 同步调用测试结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image022.png)
回页首
使用 Http 服务 HttpService
OSGi 的 HTTP 服务为我们提供了展示 OSGi 的另外一个途径,即我们可以专门提供一个 bundle 用来作为我们应用的 UI,当然这个还比较简单,只能提供基本的 HTML 服务和基本的 Servlet 服务。如果想提供复杂的 Jsp/Struts/WebWorks 等等,或者想用现有的 Web 中间件服务器例如 Tomcat/Resin/WebSphere Application Server 等,都需要另外的途径来实现,目前我提供一些基本的使用 HTTP 服务的方式。
要使用 HTTP 服务,必然有三个步骤
获取 HttpService,可以像 上述方式 那样通过 context 的
使用 HttpService 的引用注册资源或者注册 Servlet:
修改运行环境,加入支持 http 服务的 bundle
那么,接下来我们实际操作一下:
首先,在 bundle1 的 src 中建立一个新的 package,名字叫 pages,用来存放一些 HTML 的资源文件,为了提供一个基本的 HTTP 服务,我们需要提供一个 index.html,内容如下:
第二步,注册资源服务,首先我们要为 bundle1 加入 HTTP 服务的 package 引用,即修改 MANIFEST.MF 文件的 dependencies,加入包:
清单 10. 加入 HTTP 资源的注册代码
修改运行环境,在 target platform 的 bundle 列表中加入:org.eclipse.equinox.http 和 javax.servlet 这两个 bundle 保证了 HttpService 的可用性:
图 23. 加入 HttpService bundle
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image023.png)
运行,然后打开 IE 访问本机
图 24. 运行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image024.png)
加入 servlet,首先在 bundle1 建立一个包:
清单 11. MyServlet 代码
注册 servlet,在
清单 12. 注册 servlet 的代码
运行,打开 IE 访问
图 25. 运行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image025.png)
分布式部署的实现
分布式部署的实现方式一般可以通过 Web 服务、RMI 等方式,这里简单介绍一下基于 RMI 方式的分布式实现。
在 OSGi 环境中,并没有直接提供分布式部署的支持,我们可以采用 J2SE 提供的 RMI 方式来实现,但是要考虑 OSGi 的因素,即如果您希望您的服务既可以本地使用,也可以被远程访问,那么您应该这样定义接口和类:
图 26. 以被远程访问需要定义的接口和类
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image026.png)
说明:
实际操作如下:
在 bundle1 的
[b]清单 13. IAppService 接口定义
[/b]
把这个接口注册为 OSGi 标准服务以及一个 RMI 服务对象如下:
注册为标准服务:
清单 14. 注册为标准服务
注册为远程对象:
[b]清单 15. 注册为远程对象
[/b]
在 bundle2 中通过 OSGi 方式使用这个服务:
清单 16. 使用服务
通过 RMI 方式使用这个服务:
清单 17. 通过 RMI 方式使用服务
最终的运行结果如下:
图 27. 运行结果
我们不能只停留在 hello world 的层面,虽然那曾经对我们很重要 ,但是现实需要我们能够使用 OSGi 写出激动人心的应用程序,它能够被客户接受,被架构师认可,被程序员肯定。好的,那我们开始吧。下面将会着重介绍一些现实的应用程序可能需要的一些 OSGi 应用场景。
发布和使用服务
由于 OSGi 框架能够方便的隐藏实现类,所以对外提供接口是很自然的事情,OSGi 框架提供了服务的注册和查询功能。好的,那么我们实际操作一下,就在 Hello world 工程的基础上进行。
我们需要进行下列的步骤:
定义一个服务接口,并且 export 出去供其它 bundle 使用;
定义一个缺省的服务实现,并且隐藏它的实现;
Bundle 启动后,需要将服务注册到 Equinox 框架;
从框架查询这个服务,并且测试可用性。
好的,为了达到上述要求,我们实际操作如下:
定义一个新的包
osgi.test.helloworld.service,用来存放接口。单独一个 package 的好处是,您可以仅仅 export 这个 package 给其它 bundle 而隐藏所有的实现类
在上述的包中新建接口
IHello,提供一个简单的字符串服务,代码如下:
[b]清单 2. IHello
[/b]
package osgi.test.helloworld.service; public interface IHello { /** * 得到 hello 信息的接口 . * @return the hello string. */ String getHello(); }
再新建一个新的包
osgi.test.helloworld.impl,用来存放实现类。
在上述包中新建
DefaultHelloServiceImpl类,实现上述接口:
清单 3. IHello 接口实现
public class DefaultHelloServiceImpl implements IHello { @Override public String getHello() { return "Hello osgi,service"; } } |
BundleContext类实现的:
registerService(String,Object,Dictionary)注册服务对象
object到接口名
String下,可以携带一个属性字典
Dictionary;
registerService(String[],Object,Dictionary)注册服务对象
object到接口名数组
String[]下,可以携带一个属性字典
Dictionary,即一个服务对象可以按照多个接口名字注册,因为类可以实现多个接口;
我们使用第一种注册方式,修改
Activator类的
start方法,加入注册代码:
清单 4. 加入注册代码
public void start(BundleContext context) throws Exception { System.out.println("hello world"); context.registerService( IHello.class.getName(), new DefaultHelloServiceImpl(), null); } |
图 14. 选择导出的服务包
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image014.png)
另外新建一个类似于 hello world 的 bundle 叫:
osgi.test.helloworld2,用于测试
osgi.test.helloworldbundle 提供的服务的可用性;
添加 import package:在第二个 bundle 的 MANIFEST.MF 文件中,找到 dependencies > Imported packages > Add …,选择我们刚才 export 出去的 osgi.test.helloworld.service 包:
图 15. 选择刚才 export 出去的 osgi.test.helloworld.service 包
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image015.png)
查询服务:同样,OSGi 框架提供了两种查询服务的引用
ServiceReference的方法:
getServiceReference(String):根据接口的名字得到服务的引用;
getServiceReferences(String,String):根据接口名和另外一个过滤器名字对应的过滤器得到服务的引用;
这里我们使用第一种查询的方法,在
osgi.test.helloworld2bundle 的
Activator的
start方法加入查询和测试语句:
清单 5. 加入查询和测试语句
public void start(BundleContext context) throws Exception { System.out.println("hello world2"); /** * Test hello service from bundle1. */ IHello hello1 = (IHello) context.getService( context.getServiceReference(IHello.class.getName())); System.out.println(hello1.getHello()); } |
图 16. 加入对新的 bundle 的配置信息
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image016.png)
执行,得到下列结果:
图 17. 执行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image017.png)
恭喜您,成功了!
回页首
使用事件管理服务 EventAdmin
前面讲过,OSGi 规范定义了很多可用的 bundle,您尽管使用它们完成您的工作,而不必另外再发明轮子,OSGi 框架定义的事件管理服务,类似于 JMS,但是使用上比 JMS 简单。
OSGi 整个框架都离不开这个服务 ,因为框架里面全都依靠事件机制进行通信,例如 bundle 的启动、停止,框架的启动、停止,服务的注册、注销等等等等都是会发布事件给监听者,同时也在监听其它模块发来的自己关心的事件。 OSGi 框架的事件机制主要核心思想是:
用户(程序员)可以自己按照接口定义自己的事件类型
用户可以监听自己关心的事件或者所有事件
用户可以将事件同步的或者异步的提交给框架,由框架负责同步的或者异步的分发给监听者
说明:框架提供的事件服务、事件提供者、事件监听者之间的关系如下:
图 18. 事件服务、事件提供者、事件监听者之间的关系
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image018.png)
事件提供者 Publisher 可以获取 EventAdmin 服务,通过 sendEvent 同步(postEvent 异步)方式提交事件,EventAdmin 服务负责分发给相关的监听者 EventHandler,调用它们的
handleEvent方法。
这里要介绍一个新的概念 Topics,其实在 JMS 里面也有用,也就是说一个事件一般都有一个主题,这样我们的事件接收者才能按照一定的主题进行过滤处理,例如只处理自己关心的主题的事件,一般情况下主题是用类似于 Java Package 的命名方式命名的。
同步提交(sendEvent)和异步提交(postEvent) 事件的区别是,同步事件提交后,等框架分发事件给所有事件接收者之后才返回给事件提交者,而异步事件则一经提交就返回了,分发在另外的线程进行处理。
下面的程序演示了事件的定义、事件的发布、事件处理,同时还演示了同步和异步处理的效果,以及运行环境的配置。
(约定
osgi.test.helloworld为 bundle1,
osgi.test.helloworld2为 bundle2)
图 19. 同步和异步处理演示
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image019.png)
在 bundle1 中的 MANIFEST.MF 的 dependency 页面中定义引入新的包:
org.osgi.service.event。
在 bundle1 中的
osgi.test.helloworld.event包中定义新的类
MyEvent,如下(注意其中的 topic 定义的命名方式):
清单 6. 定义新的类 MyEvent
import java.util.Dictionary; import org.osgi.service.event.Event; public class MyEvent extends Event { public static final String MY_TOPIC = "osgi/test/helloworld/MyEvent"; public MyEvent(String arg0, Dictionary arg1) { super(MY_TOPIC, arg1); } public MyEvent() { super(MY_TOPIC, null); } public String toString() { return "MyEvent"; } } |
DefaultHelloServiceHandler类的
getHello方法中,加入提交事件的部分,这样 bundle2 在调用这个服务的时候,将触发一个事件,由于采用了 Post 方式,应该是立刻返回的,所以在
postEvent前后打印了语句进行验证。
清单 7. getHello 方法
import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.event.EventAdmin; @Override public String getHello() { //post a event ServiceReference ref = context.getServiceReference(EventAdmin.class.getName()); if(ref!=null) { eventAdmin = (EventAdmin)context.getService(ref); if(eventAdmin!=null) { System.out.println("post event started"); eventAdmin.postEvent(new MyEvent()); System.out.println("post event returned"); } } return "Hello osgi,service"; } |
MyEventHandler类,用来处理事件,这里故意加入了一个延迟,是为了测试异步事件的调用,实现如下:
清单 8. MyEventHandler类
import org.osgi.service.event.Event; |
Activator类中加入此监听器,也就是调用
context.registerService方法注册这个监听服务,和普通服务的区别是要带一个监听事件类型的 topic,这里列出
Activator类的
start方法:
清单 9. start 方法
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Hashtable; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import osgi.test.helloworld.event.MyEvent; import osgi.test.helloworld.service.IAppService; import osgi.test.helloworld.service.IHello; public void start(BundleContext context) throws Exception { System.out.println("hello world2"); /** * 添加事件处理器 . */ String[] topics = new String[] {MyEvent.MY_TOPIC}; Hashtable<String,String[]> ht = new Hashtable<String,String[]>(); ht.put(EventConstants.EVENT_TOPIC, topics); EventHandler myHandler = new MyEventHandler(); context.registerService( EventHandler.class.getName(), myHandler, ht); System.out.println("event handler registered"); /** * Test hello service from bundle1. */ IHello hello1 = (IHello) context.getService( context.getServiceReference(IHello.class.getName())); System.out.println(hello1.getHello()); } |
org.eclipse.osgi.services
org.eclipse.equinox.event
好了一切准备好了,执行:
图 20. 执行
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image020.png)
可以看到,
post事件后,不等事件真的被处理完成,就返回了,事件处理在另外的线程执行,最后才打印处理完成的语句。然后
ss看一下,目前我们已经有五个 bundle 在运行了:
图 21. ss 查询
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image021.png)
OK,修改代码以测试同步调用的情况,我们只需要把提交事件的代码由
postEvent修改为
sendEvent即可。其它不变,测试结果如下:
图 22. 同步调用测试结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image022.png)
回页首
使用 Http 服务 HttpService
OSGi 的 HTTP 服务为我们提供了展示 OSGi 的另外一个途径,即我们可以专门提供一个 bundle 用来作为我们应用的 UI,当然这个还比较简单,只能提供基本的 HTML 服务和基本的 Servlet 服务。如果想提供复杂的 Jsp/Struts/WebWorks 等等,或者想用现有的 Web 中间件服务器例如 Tomcat/Resin/WebSphere Application Server 等,都需要另外的途径来实现,目前我提供一些基本的使用 HTTP 服务的方式。
要使用 HTTP 服务,必然有三个步骤
获取 HttpService,可以像 上述方式 那样通过 context 的
getService方法获得引用;
使用 HttpService 的引用注册资源或者注册 Servlet:
registerResources:注册资源,提供本地路径、虚拟访问路径和相关属性即可完成注册,客户可以通过虚拟访问路径 + 资源名称访问到资源
registerServlet:注册 Servlet,提供标准 Servlet 实例、虚拟访问路径、相关属性以及 HttpContext(可以为 null)后即可完成注册,客户可以直接通过虚拟访问路径获取该 Servlet 的访问
修改运行环境,加入支持 http 服务的 bundle
那么,接下来我们实际操作一下:
首先,在 bundle1 的 src 中建立一个新的 package,名字叫 pages,用来存放一些 HTML 的资源文件,为了提供一个基本的 HTTP 服务,我们需要提供一个 index.html,内容如下:
<html> <h1>hello osgi http service</h1> </html> |
org.osgi.service.http;version="1.2.0",然后在
Activator类的
start方法中加入 HTTP 资源的注册:
清单 10. 加入 HTTP 资源的注册代码
httpService = (HttpService)context.getService (context.getServiceReference(HttpService.class.getName())); httpService.registerResources("/", "/pages", null); |
图 23. 加入 HttpService bundle
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image023.png)
运行,然后打开 IE 访问本机
http://localhost/index.html:
图 24. 运行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image024.png)
加入 servlet,首先在 bundle1 建立一个包:
osgi.test.hellworld.servlet,建立一个新的类:
MyServlet,要从
HttpServlet基类继承,实现其
doGet方法,如下:
清单 11. MyServlet 代码
import java.io.IOException; import java.util.Date; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyServlet extends HttpServlet { /** * 实现测试 . * @param request the req. * @param response the res. * @throws IOException io exception. */ public void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException { response.getWriter() .write("hello osgi http servlet.time now is "+new Date()); } } |
Activator类的
start方法中加入注册 servlet 的代码,如下:
清单 12. 注册 servlet 的代码
MyServlet ms = new MyServlet(); httpService.registerServlet("/ms", ms, null, null); |
http://localhost/ms后得到结果:
图 25. 运行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image025.png)
分布式部署的实现
分布式部署的实现方式一般可以通过 Web 服务、RMI 等方式,这里简单介绍一下基于 RMI 方式的分布式实现。
在 OSGi 环境中,并没有直接提供分布式部署的支持,我们可以采用 J2SE 提供的 RMI 方式来实现,但是要考虑 OSGi 的因素,即如果您希望您的服务既可以本地使用,也可以被远程访问,那么您应该这样定义接口和类:
图 26. 以被远程访问需要定义的接口和类
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image026.png)
说明:
Remote接口是 J2SE 定义的远程对象必须实现的接口;
IAppService接口是 OSGi 服务接口,继承了
Remote接口,即定义方式为:
public interface IAppService extends Remote |
AppServiceImpl实现了
IAppService接口,此外注意里面的方法都抛出
RemoteException异常;
实际操作如下:
在 bundle1 的
service包中加入
IAppService接口的定义,继承自
Remote接口,定义个方法:
[b]清单 13. IAppService 接口定义
[/b]
public interface IAppService extends Remote { /** * 得到一个远程服务的名称 . * @return . * @throws RemoteException . */ String getAppName() throws RemoteException; }
把这个接口注册为 OSGi 标准服务以及一个 RMI 服务对象如下:
注册为标准服务:
清单 14. 注册为标准服务
IAppService appService = new DefaultAppServiceImpl(context); context.registerService( IAppService.class.getName(), appService, null); |
[b]清单 15. 注册为远程对象
[/b]
/** * 启动 rmi server . * @param service the service. * @throws RemoteException re. */ private void startRmiServer(IAppService service) throws RemoteException { if(registry == null) { registry = LocateRegistry.createRegistry(1099); } // 注册 appService 远程服务 . IAppService theService = (IAppService)UnicastRemoteObject.exportObject(service,0); registry.rebind("appService", theService); }
在 bundle2 中通过 OSGi 方式使用这个服务:
清单 16. 使用服务
IAppService appService = (IAppService)context.getService( context.getServiceReference(IAppService.class.getName())); System.out.println(appService.getAppName()); |
清单 17. 通过 RMI 方式使用服务
String host = "127.0.0.1"; int port = 1099; try { Registry registry = LocateRegistry.getRegistry(host,port); appServiceStub = (IAppService) registry.lookup("appService"); } catch (Exception e) { e.printStackTrace(); } System.out.println("rmi:"+appServiceStub.getAppName()); |
图 27. 运行结果
![](http://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/image027.png)
相关文章推荐
- 开发一个真实的 OSGi 应用程序
- 开发一个真实的 OSGi 应用程序
- 开发一个真实的 OSGi 应用程序
- Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架
- 为 WebSphere Application Server 开发企业 OSGi 应用程序
- 第7章 SportsStore:一个真实的应用程序 — 精通MVC 3 框架
- 如何去开发一个web应用程序
- OSGI企业应用开发(十五)基于Spring、Mybatis、Spring MVC实现一个登录应用
- Silverlight开发常见的一个小问题:2103错误 应用程序无效或格式不正确: 请查看清单
- Eclipse 开发 Android 应用程序关于SVN插件的一个小事项
- 第7章 SportsStore — 一个真实的应用程序
- Java应用程序开发电子商务 - 一个不错的选择
- Delphi for iOS开发指南(3):创建一个FireMonkey iOS应用程序
- 【BluePrint】用OSGi 应用程序开发和工作的最佳实践
- 1 开发一个注重性能的JDBC应用程序不是一件容易的事. 当你的代码运行很慢的时候JDBC驱动程序并不会抛出异常告诉你。 本系列的性能提示将为改善JDBC应用程序的性能介绍一些基本的指导原则,这其中的原则已经被许多现有的JDBC应用程序编译运行并验证过。 这些指导原则包括: 正确的使用数据库MetaData方法 只获取需要的数据 选用最佳性能的功能 管理连
- Become.com的 Web Crawler: 一个超大规模的Java应用程序(想开发自己的搜索引擎增值服务的必读)
- OSGI企业应用开发(十五)基于Spring、Mybatis、Spring MVC实现一个登录应用
- Delphi for iOS开发指南(3):创建一个FireMonkey iOS应用程序
- OSGI笔记(二) 真实的 OSGi 应用程序
- 用K2 smartforms开发一个应用程序究竟比ASP.NET快多少?