声明:除了人人IT網 外其他个人或企业都可转载
写一个HK2组件
HK2是轻量级、可扩展的Glassfish Server 内核。为了和GlassFish 服务器(glassfish中其他服务和组件)交互,就需要编写基于HK2的插件。在HK2组件模型中,一个组件的功能是通过 服务接口-服务实现 的模式声明的。一个HK2服务接口 标识并描述了一个构建模块或者应用程序扩展点。HK2服务实现 实现了 HK2服务接口。
HK2 组件模型
(HK2)提供了一个模块系统和组件模型来建立复杂的软件系统。HK2形成了GlassFish服务器的核心的架构。
该模块系统负责实例化构成应用程序功能的类。HK2运行时通过创建对象来填充该模块系统。模块系统通过以下方式装配对象:
* 实例化一个新的对象注入到需要这个对象的对象中。
* 为这个对象注入所需的配置信息。
* 使新建的对象可用,这样这些对象就可以注入到其他需要这些对象的对象中。
HK2组件模型中的服务
一个HK2服务(服务接口)标识并描述了一个构建模块或者应用程序扩展点。服务是一个普通的Java对象(POJO)具有以下特点:
* 该对象(类)实现了一个接口。
* 对象(类)应该在JAR的meta - inf / services文件中声明。
为了清晰地划分服务接口及其实现,HK2运行时需要以下信息:
* 哪些接口是服务接口。
* 哪些实现类是该服务接口的服务实现。
接口:通过标记一个org.jvnet.hk2.annotation.Contract类型的注释来标识这个接口是 服务接口(能被HK2认识的接口)。
Contract注解定义:
@Retention(RUNTIME) @Target(TYPE) public @interface Contract { }实现:服务接口的实现应该标记一个org.jvnet.hk2.annotations.Service类型的注释来标识这个实现是 实现了服务接口的服务实现(能被HK2识别的实现)。
Service注释定义:
@Retention(RUNTIME) @Target(TYPE) public @interface Service { ... }
HK2运行时
一旦服务定义完成,HK2运行时就可以实例化或检索服务的实例。每个服务实例有一个服务范围,可以指定为作用于singleton的,每个线程的,每个应用程序的,或一个自定义的范围。
服务的作用范围
您可以通过增加了一个org.jvnet.hk2.annotations.Scoped 注释到标有@service注释的类级别的实现类上指定该服务的服务范围,范围也是一种服务,所以范围服务可以用户自定义并在被其他服务调用之前添加到HK2运行时中。每个范围负责它绑定的服务实例的存储。因此,HK2运行时不依赖预定义的范围(尽管它有一些预定义的)。
scope注释定义
@Contract public abstract class Scope { public abstract ScopeInstance current(); }
下面的代码,展示了如何使用预定义范围(Singleton级别的):
@Service public Singleton implements Scope { ... } @Scope(Singleton.class) @Service public class SingletonService implements RandomContract { ... }您可以定义一个新的范围实现并在你的@service实现类上使用,这样帮助你理解,HK2运行时使用范围实例存储和检索服务实例绑定到范围。
在HK2中实例化组件的方法
不要调用new方法来实例化组件。而是通过ComponentManager实例来检索组件。
使用ComponentManager实例的最简单方式是调用getComponent(ClassT contract)方法
public <T> T getComponent(Class<T> clazz) throws ComponentException;
HK2生命周期接口
组件可以在初始化和销毁事件发生过程中,添加插面逻辑,这是通过实现org.jvnet.hk2.component.PostConstruct或 org.jvnet.hk2.component.PreDestroy接口完成的,通过实现接口而不使用注释是出于性能的考虑。
PostConstruct 接口定义了一个唯一的方法postConstruct(),这个方法在组件初始化并且组件的依赖被注入后调用。
PreDestroy 接口定义了一个唯一的方法preDestroy(),这个方法在组件从系统移除前调用。下面是实现了这两个接口的示例:
@Service(name="com.example.container.MyContainer") public class MyContainer implements Container, PostConstruct, PreDestroy { @Inject Logger logger; ... public void postConstruct() { logger.info("Starting up."); } public void preDestroy() { logger.info("Shutting down."); } }
控制反转
控制反转(IoC)指的是一个软件系统编程方式, 系统的行为是由组成这个系统的一些独立的、离散的组件在运行时的功能决定的。这种体系结构不同于传统风格的软件架构,在传统的系统构架中系统的组件是在设计阶段指定的。使用IOC设计模式,离散的组件负责响应上层组件发出的事件(如上层组件要求注入其他组件并调用其方法)来执行操作。而在执行这些操作,组件又通常依赖其他组件提供其他操作。在一个实现IOC的系统中,通常组件使用注入的方式来获得系统中其他组件和萃取的方式使组件注入到系统供其他组件获取。
注入HK2组件
服务通常依赖于其他服务来执行他们的任务。HK2运行时通过在标识了@Contract 的服务实现的类中使用@org.jvnet.hk2.annotations.Inject 注释来完成服务实例的注入。Inject 注释可以置于在成员变量或setter方法之上,目标服务在调用服务实例时,通过component manager来完成检索和注入。
下面的例子展示了在成员变量级别使用@inject注释
@Inject ConfigService config;下面的例子展示了在setter方法级别使用@inject注释
@Inject public void set(ConfigService svc) {...}注入可以通过使用了name和scope的有效服务来进一步确定要注入到服务实现的服务。如:
@Inject(Scope=Singleton.class, name="deploy") AdminCommand deployCommand;
从habitat中萃取值
尽管所有的服务都自动存在一个范围中,以便稍后被检索,但一个组件可能超出它的范围被其他组件获取,简单上的做法是使用工厂服务。然而HK2运行时通过在所有成员变量和getter方法上标识@Extract来完成萃取。
HK2的实例化级联
确定一个类作为插件(附加组件)
使用Apache Maven构建工具开发HK2组件
如果你使用Maven2(我用的是maven2.2.1)来构建HK2组件。调用auto-depends maven插件以便在自动构建过程中生成META-INF/services文件。下面是一个例子
pom中调用auto-depends插件:
<plugin> <groupId>com.sun.enterprise</groupId> <artifactId>hk2-maven-plugin</artifactId> <configuration> <includes> <include>com/sun/enterprise/v3/**</include> </includes> </configuration> </plugin>META-INF/services 文件生成:
package com.sun.v3.annotations; @Contract public interface Startup {...} package com.wombat; @Contract public interface RandomContract {...} package com.sun.v3; @Service public class MyService implements Startup, RandomContract, PropertyChangeListener { ... }
生成 META-INF/services 文件的内容:
com.sun.v3.annotations.Startup com.wombat.RandomContract