创建并部署MBean以使用JMX控制台管理服务。 公开服务属性和操作,以便执行管理任务。
有关使用JMX控制台的信息,请参见 使用JMX控制台监控服务器资源.
在Apache Felix平台上,您可以将MBean部署为OSGi服务。 在OSGi Service Registry中注册MBean服务时, Aries JMX白板模块会自动向MBean Server注册MBean。 然后,MBean可供JMX控制台使用,该控制台会公开公共属性和操作。
为管理CQ5或CRX资源而创建的MBean基于javax.management.DynamicMBean接口。 要创建它们,请遵循JMX规范中规定的常规设计模式:
除了定义管理接口外,该接口还定义了OSGi服务接口。 实现类实现OSGi服务。
此 com.adobe.granite.jmx.annotation 包提供了多个注释和类,用于轻松将MBean元数据提供给JMX控制台。 使用这些注释和类,而不是直接向MBean的MBeanInfo对象添加信息。
注释
将注释添加到管理界面以指定MBean元数据。 该信息显示在JMX控制台中,供每个已部署的实现类使用。 提供了以下注释(有关完整信息,请参阅 com.adobe.granite.jmx.annotation JavaDocs):
描述: 提供MBean类或方法的说明。 在类声明上使用时,该说明将显示在MBean的JMX控制台页面上。 在方法上使用时,说明显示为相应属性或操作的悬停文本。
影响: 方法的影响。 有效参数值是由定义的字段 javax.management.MBeanOperationInfo.
名称: 指定操作参数显示的名称。 使用此注释可覆盖界面中使用的方法参数的实际名称。
OpenTypeInfo: 指定用于在JMX控制台中表示复合数据或表格数据的类。 与Open MBean一起使用
TabularTypeInfo: 用于对用于表示表格式数据的类进行注释。
类
提供了用于创建使用您添加到其接口中的注释的动态MBean的类:
通常,您的MBean反映了您要管理的OSGi服务。 在Felix平台上,您可以像在其他Java服务器平台上部署一样创建MBean。 主要区别在于,您可以使用注释来指定MBean信息:
以下示例MBean提供了有关CRX存储库的信息。 该界面使用Description注释向JMX控制台提供信息。
package com.adobe.example.myapp;
import com.adobe.granite.jmx.annotation.Description;
@Description("Example MBean that exposes repository properties.")
public interface ExampleMBean {
@Description("The name of the repository.")
String getRepositoryName();
@Description("The vendor of the repository.")
String getRepositoryVendor();
@Description("The URL of repository vendor.")
String getVendorUrl();
}
实施类使用SlingRepository服务检索有关CRX存储库的信息。
package com.adobe.example.myapp;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
import javax.management.*;
public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {
@Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private SlingRepository repository;
public ExampleMBeanImpl() throws NotCompliantMBeanException {
super(ExampleMBean.class);
}
public String getRepositoryName() {
return repository.getDescriptor("jcr.repository.name");
}
public String getRepositoryVendor() {
return repository.getDescriptor("jcr.repository.vendor");
}
public String getVendorUrl() {
return repository.getDescriptor("jcr.repository.vendor.url");
}
}
下图显示了JMX控制台中此MBean的页面。
当您将MBean注册为OSGi服务时,将自动向MBean服务器注册它们。 要在CQ5上安装MBean,请将其包含在捆绑包中,并像导出任何其他OSGi服务一样导出MBean服务。
除了与OSGi相关的元数据之外,还必须提供Aries JMX白板模块在MBean服务器中注册MBean所需的元数据:
DynamicMBean接口的名称: 声明MBean服务实现 javax.management.DynamicMBea
n接口。 此声明通知Aries JMX白板模块,该服务是一个MBean服务。
MBean域和密钥属性: 在Felix上,您可以将此信息作为MBean的OSGi服务的属性提供。 该信息与您通常在 javax.management.ObjectName
对象。
当您的MBean反映为单个服务时,只需要一个MBean服务实例。 在这种情况下,如果您使用Felix SCR Maven插件,则可以使用MBean实现类上的Apache Felix服务组件运行时(SCR)注释来指定与JMX相关的元数据数据。 要实例化多个MBean实例,您可以创建另一个类来注册MBean的OSGi服务。 在这种情况下,与JMX相关的元数据在运行时生成。
单MBean
可以在设计时为其定义所有属性和操作的MBean可以使用MBean实现类中的SCR注释进行部署。 在以下示例中, value
的属性 Service
annotation声明服务将实施 DynamicMBean
界面。 此 name
的属性 Property
annotation指定JMX域和键属性。
package com.adobe.example.myapp;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
import javax.management.*;
@Component(immediate = true)
@Property(name = "jmx.objectname", value="com.adobe.example:type=CRX")
@Service(value = DynamicMBean.class)
public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {
@Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private SlingRepository repository;
public ExampleMBeanImpl() throws NotCompliantMBeanException {
super(ExampleMBean.class);
}
public String getRepositoryName() {
return repository.getDescriptor("jcr.repository.name");
}
public String getRepositoryVendor() {
return repository.getDescriptor("jcr.repository.vendor");
}
public String getVendorUrl() {
return repository.getDescriptor("jcr.repository.vendor.url");
}
}
多个MBean服务实例
要管理托管服务的多个实例,您需要创建相应MBean服务的多个实例。 此外,在启动或停止托管实例时,应创建或删除MBean服务实例。 您可以创建一个MBean管理器类以在运行时实例化MBean服务,并管理服务生命周期。
使用BundleContext将MBean注册为OSGi服务。 在用作BundleContext.registerService方法参数的Dictionary对象中包含与JMX相关的信息。
在以下代码示例中,ExampleMBean服务是以编程方式注册的。 componentContext对象是ComponentContext,它提供对BundleContext的访问。
Dictionary mbeanProps = new Hashtable();
mbeanProps.put("jmx.objectname", "com.adobe.example:type=CRX");
ExampleMBeanImpl mbean = new ExampleMBeanImpl();
ServiceRegistration serviceregistration =
componentContext.getBundleContext().registerService(DynamicMBean.class.getName(), mbean, mbeanProps);
下一部分中的示例MBean提供了更多详细信息。
当服务配置存储在存储库中时,MBean服务管理器非常有用。 管理器可以检索服务信息,并使用它来配置和创建相应的MBean。 经理类还可以侦听存储库更改事件并相应地更新MBean服务。
此示例中的MBean提供了有关存储在存储库中的CQ5工作流模型的信息。 MBean管理器类基于存储在存储库中的工作流模型创建MBean,并在运行时注册其OSGi服务。 此示例由包含以下成员的单个包组成:
注意: 为简单起见,此示例中的代码不会执行日志记录或响应抛出的异常。
WorkflowMBeanManagerImpl包括组件激活方法。 激活组件后,方法会执行以下任务:
MBean元数据显示在JMX控制台中,带有com.adobe.example域、workflow_model类型,而Properties是工作流模型配置节点的路径。
此示例需要MBean接口和实施,该接口和实施反映在 com.day.cq.workflow.model.WorkflowModel
界面。 MBean非常简单,因此该示例可以专注于设计的配置和部署方面。 MBean公开单个属性,即模型名称。
package com.adobe.example.myapp.api;
import com.adobe.granite.jmx.annotation.Description;
@Description("Example MBean that exposes Workflow model properties.")
public interface WorkflowMBean {
@Description("The name of the Workflow model.")
String getModelName();
}
package com.adobe.example.myapp.impl;
import javax.management.NotCompliantMBeanException;
import com.day.cq.workflow.model.WorkflowModel;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;
public class WorkflowMBeanImpl extends AnnotatedStandardMBean implements WorkflowMBean {
WorkflowModel model;
protected WorkflowMBeanImpl(WorkflowModel inmodel)
throws NotCompliantMBeanException {
super(WorkflowMBean.class);
model=inmodel;
}
public String getModelName() {
return model.getTitle();
}
}
WorkflowMBeanManager服务包括用于创建WorkflowMBean服务的组件激活方法。 该服务实施包括以下方法:
WorkflowMBeanManager实施仅为激活组件时存在的模型配置创建MBean服务。 更强大的实施可监听有关新模型配置以及现有模型配置的更改或删除的存储库事件。 发生更改时,管理员可以创建、修改或删除相应的WorkflowMBean服务。
package com.adobe.example.myapp.api;
public interface WorkflowMBeanManager {
}
package com.adobe.example.myapp.impl;
import java.util.*;
import org.apache.felix.scr.annotations.*;
import javax.jcr.Session;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.management.ObjectName;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.workflow.WorkflowService;
import com.day.cq.workflow.WorkflowSession;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.example.myapp.api.WorkflowMBeanManager;
/**Instantiates and registers WorkflowMBean services */
@Component(immediate=true)
@Service(value=WorkflowMBeanManager.class)
public class WorkflowMBeanManagerImpl implements WorkflowMBeanManager {
//The ComponentContext provides access to the BundleContext
private ComponentContext componentContext;
//Use the SlingRepository service to read model nodes
@Reference
private SlingRepository repository = null;
//Use the WorkflowService service to create WorkflowModel objects
@Reference
private WorkflowService workflowservice = null;
private Session session;
//Details about model nodes
private static final String MODEL_ROOT ="/etc/workflow/models";
private static final String MODEL_NODE = "model";
private Set<String> modelIds = new HashSet<String>();
//Storage for ServiceRegistrations for MBean services
private Collection<ServiceRegistration> mbeanRegistrations= new Vector<ServiceRegistration>(0,1);
@Activate
protected void activate(ComponentContext ctx) {
//Traverse the repository and load the model nodes
try {
session = repository.loginAdministrative(null);
// load and store model node paths
if (session.nodeExists(MODEL_ROOT)) {
getModelIds(session.getNode(MODEL_ROOT));
}
//Create MBeans for each model
for(String modid: modelIds){
makeMBean(modid);
}
}catch(Exception e){ }
}
/**
* Add JMX domain and key properties to a collection
* Instantiate a WorkflowModel and its WorkflowMBeanImpl object
* Register the MBean OSGi service
*/
private void makeMBean(String modelId) {
// create MBean for the model
try {
Dictionary<String, String> mbeanProps = new Hashtable<String, String>();
//These properties appear on the JMX Console home page
mbeanProps.put("jmx.objectname", "com.adobe.example:type=workflow_model,id=" + ObjectName.quote(modelId));
WorkflowSession wfsession = workflowservice.getWorkflowSession(session);
WorkflowMBeanImpl mbean = new WorkflowMBeanImpl(wfsession.getModel(modelId));
ServiceRegistration serviceregistration = componentContext.getBundleContext().registerService(WorkflowMBean.class.getName(), mbean, mbeanProps);
//Store the ServiceRegistration objects for deactivation
mbeanRegistrations.add(serviceregistration);
} catch (Throwable t) {}
}
/**
* Traverses the repository branch below a given Node. Stores the path of each model node.
*/
private void getModelIds(Node node) throws RepositoryException {
try{
NodeIterator iter = node.getNodes();
while (iter.hasNext()) {
Node n = iter.nextNode();
//Look for "jcr:content" nodes
if (n.getName().equals("jcr:content")) {
//get the path of the model node and save it
if(n.hasNode(MODEL_NODE)){
modelIds.add(n.getNode(MODEL_NODE).getPath());
}
} else{
//Scan child nodes
getModelIds(n);
}
}
}catch(Exception e){ }
}
/**
* Log out of the JCR session and unregister WorkflowMBean services
*/
@Deactivate
protected void deactivate() {
session.logout();
session=null;
for(ServiceRegistration sr:mbeanRegistrations){
sr.unregister();
}
}
}
为方便起见,您可以将以下XML代码复制并粘贴到项目pom.xml文件中,以生成组件包。 POM引用了多个必需的插件和依赖关系。
插件:
注意: 在编写时,maven scr插件与Eclipse的m2e插件不兼容。 (请参阅 Felix bug 3170.) 要使用Eclipse IDE,请安装Maven并使用命令行界面执行生成。
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.adobe.example.myapp</groupId>
<artifactId>workflow-mbean</artifactId>
<version>0.0.2-SNAPSHOT</version>
<name>mbean-simple</name>
<url>www.adobe.com</url>
<description>A simple MBean</description>
<packaging>bundle</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.7.2</version>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.3</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>com.adobe.example.myapp.*;version=${project.version}</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
<version>2.0.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<version>1.6.1-R1236132</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.api</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.adobe.granite</groupId>
<artifactId>com.adobe.granite.jmx</artifactId>
<version>0.1.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-mobile-api</artifactId>
<version>5.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.day.cq.workflow</groupId>
<artifactId>cq-workflow-api</artifactId>
<version>5.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
将以下配置文件添加到您的maven设置文件以使用公共Adobe存储库。
<profile>
<id>adobe-public</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<releaseRepository-Id>adobe-public-releases</releaseRepository-Id>
<releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>
<releaseRepository-URL>https://repo1.maven.org/maven2/com/adobe/</releaseRepository-URL>
</properties>
<repositories>
<repository>
<id>adobe-public-releases</id>
<name>Adobe Public Repository</name>
<url>https://repo1.maven.org/maven2/com/adobe/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>adobe-public-releases</id>
<name>Adobe Public Repository</name>
<url>https://repo1.maven.org/maven2/com/adobe/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>