使用JMX主控台建立和部署MBeans以管理服務。 公開服務屬性和操作,以便執行管理任務。
有關使用JMX控制台的資訊,請參見使用JMX控制台監視伺服器資源。
在Apache Felix平台上,您可將MBean部署為OSGi服務。 在OSGi服務註冊表中註冊MBean服務時,Aries JMX白板模組將自動向MBean伺服器註冊MBean。 然後MBean便可用於JMX控制台,該控制台會顯示公共屬性和操作。
您為管理CQ5或CRX資源而建立的MBeans是以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平台上,您建立MBean的方式與在其他Java伺服器平台上部署的方式相同。 主要區別是,您可以使用注釋來指定MBean資訊:
以下示例MBean提供了有關CRX儲存庫的資訊。 此介面使用「說明」註解來提供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反映單一服務時,只需要MBean服務的單個實例。 在本例中,如果您使用Felix SCR Maven增效模組,則可以使用MBean實作類別上的Apache Felix Service Component Runtime(SCR)註解來指定JMX相關元資料。 要實例化多個MBean實例,可以建立另一個類,用於執行MBean的OSGi服務的註冊。 在此例中,JMX相關中繼資料會在執行時期產生。
單一MBean
可在設計時為其定義所有屬性和操作的MBeans可使用MBean實現類中的SCR注釋進行部署。 在以下示例中, Service
注釋的value
屬性聲明服務實現DynamicMBean
介面。 Property
注釋的name
屬性指定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服務。 在Dictionary物件中加入您用作BundleContext.registerService
方法引數的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類型,而「屬性」是工作流程模型設定節點的路徑。
此示例要求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引用了幾個必需的插件和從屬關係。
外掛程式:
注意: 在編寫時,mavenscr外掛程式與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>
將下列設定檔新增至您的主版設定檔案,以使用公用的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://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL>
</properties>
<repositories>
<repository>
<id>adobe-public-releases</id>
<name>Adobe Basel Public Repository</name>
<url>https://repo.adobe.com/nexus/content/groups/public</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 Basel Public Repository</name>
<url>https://repo.adobe.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>