当前位置: 首页 > news >正文

德阳定制建站网站建设制作搜索引擎入口官网

德阳定制建站网站建设制作,搜索引擎入口官网,微信做网站网站,东莞营销推广公司【0】README1#xff09;本文部分文字描述转自#xff1a;“深入剖析tomcat”#xff0c;旨在学习“tomcat(20)基于JMX的管理” 的相关知识#xff1b;2#xff09;晚辈我在tomcat上部署web 项目以测试JMX管理 tomcat 容器bean的效果#xff0c;结果运行不成功#xff0…【0】README1本文部分文字描述转自“深入剖析tomcat”旨在学习“tomcat(20)基于JMX的管理” 的相关知识 2晚辈我在tomcat上部署web 项目以测试JMX管理 tomcat 容器bean的效果结果运行不成功详情参见文末图片 3for complete source code, please visit  https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter20【1】JMX 简介1introJMX Java Management Extensions JMX规范 JMX管理扩展2既然ContainerServlet接口已经有利用Manager应用程序访问Catalina的内部对象那么为什么还要用 JMX呢因为JMX 提供了比 ContainerServlet接口更灵活的方法来管理tomcat。许多基于服务器的应用程序如tomcat JBossJONASGeronimo等都使用了JMX 技术来管理各自的资源 3JMX规范定义了管理java 对象的的公开标准。如tomcat 4  和 tomcat5 都使用JMX 来启用 servlet容器中的各种对象如 Server对象 Host对象Context对象Valve对象等4可由JMX 管理的资源如果一个java对象可以由一个遵循JMX 规范的管理器应用程序管理那么这个java对象称为一个可由JMX 管理的资源干货——可由JMX 管理的资源实际上一个可由JMX 管理的资源可以是一个应用程序一种实现一个服务一个设备一个用户等。一个可由JMX管理的资源也可以由 java 编写并提供一个相应的java包装 4.1若要使一个java对象成为一个可由JMX 管理的资源则必须创建Managed Bean 或 MBean对象干货——引入了MBean 4.2MBean会提供它所管理的一些java对象的属性和方法供管理应用程序使用管理应用程序本身并不能直接访问托管的java对象因此可以选择java对象 的哪些属性和和方法可以由管理应用程序使用 4.3当拥有了一个MBean类后需要将其实例化并将其注册到另一个作为 MBean服务器的java对象中MBean 服务器中保存了应用程序中注册的所有MBean。管理应用程序通过MBean服务器来访问 MBean实例干货——MBean 服务器中保存了应用程序中注册的所有MBean。管理应用程序通过MBean服务器来访问 MBean实例 4.4管理应用程序好比web 浏览器 而MBean 服务器好比 servlet容器 5共有4种类型的MBean标准类型动态类型 开放类型模型类型我们对模型类型尤其感兴趣因为 Catalina中就使用了 模型类型的MBean6从结构上讲JMX 规范分为3层 设备层代理层 和 分布式服务层6.1MBean服务器位于代理层MBean 位于设备层分布式服务层会在 JMX 规范将来的版本中涉及 6.2设备层规范定义了编写可由JMX 管理的资源的标准即如何编写MBean 6.3代理层定义了创建代理的规范代理封装了 MBean服务器提供了处理MBean的服务代理和它所管理的MBean 通常都位于同一个java 虚拟机中。由于JMX 规范附带了一个参考实现所以并不需要自己编写MBean 服务器 Attention可以从下面的地址中下载JMX 规范和参考实现http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html, MX4J是一个开源版本的JMX下载地址为http://mx4j.sourceforge.net/【2】JMX API1JMX的参考实现包含一个核心java库:这个库位于 javax.management 包 和 JMX 编程中具有特定功能的其他包下【2.1】 MBeanServer类是 javax.management.MBeanServer 接口的实例1要创建一个 MBeanServer的实例只需要调用 javax.management.MBeanServerFactory 类的 createMBean()方法2要将一个 MBean注册到 MBean服务器中可以调用 MBeanServer.registerMBean()方法下面是 registerMBean()方法的签名public interface MBeanServer extends MBeanServerConnection { //javax.management.loading.ClassLoaderRepository.MBeanServerpublic ObjectInstance registerMBean(Object object, ObjectName name)throws InstanceAlreadyExistsException, MBeanRegistrationException,NotCompliantMBeanException; }对以上代码的分析AnalysisA1要调用registerMBean方法需要传入一个待注册的MBean实例和一个 ObjectName 实例 A2ObjectName实例与 HashMap中的键类似它可以唯一标识一个 MBean实例 A3registerMBean方法返回一个ObjectInstance 实例。java.management.ObjectInstance 类封装了一个 MBean实例的对象名称和它的类名 public class ObjectInstance implements Serializable {private static final long serialVersionUID -4099952623687795850L;private ObjectName name;private String className; public ObjectInstance(String objectName, String className)throws MalformedObjectNameException {this(new ObjectName(objectName), className);} public ObjectInstance(ObjectName objectName, String className) {if (objectName.isPattern()) {final IllegalArgumentException iae new IllegalArgumentException(Invalid name-objectName.toString());throw new RuntimeOperationsException(iae);}this.name objectName;this.className className;} public boolean equals(Object object) {if (!(object instanceof ObjectInstance)) {return false;}ObjectInstance val (ObjectInstance) object;if (! name.equals(val.getObjectName())) return false;if (className null)return (val.getClassName() null);return className.equals(val.getClassName());}public int hashCode() {final int classHash ((classNamenull)?0:className.hashCode());return name.hashCode() ^ classHash;} public ObjectName getObjectName() {return name;} public String getClassName() {return className;} public String toString() {return getClassName() [ getObjectName() ];}} 3要想获取 MBean 实例或匹配某个模式的一组MBean实例可以使用 MBeanServer接口提供的两个方法分别是 queryNames()方法和 queryMBeans()方法3.1queryNames()方法 返回一个java.util.Set 实例其中包含了匹配某个指定模式对象名称的一组MBean 实例的对象名称其方法签名为 public SetObjectName queryNames(ObjectName name, QueryExp query); 对以上代码的分析AnalysisA1参数query 指定了过滤条件 A2若参数name为null 或者没有域而且指定了key 属性那么会返回已经注册的MBean实例的所有 ObjectName实例。如果参数 queyr为null则不会对查找对象进行过滤 3.2queryMBeans()方法其方法签名如下 public SetObjectInstance queryMBeans(ObjectName name, QueryExp query); 对以上代码的分析Analysis一旦获得了所需要 的MBean实例的对象名称就可以操作托管资源在 MBean 实例中提供的属性或调用其方法 4可以通过调用MBeanServer.invoke()方法 调用已经注册的 MBean实例的任何方法。4.1MBeanServer.getAttribute()方法 和 setAttribute()方法用于获取或设置已经注册的 MBean实例的属性 【2.2】ObjectName属性1introMBean实例注册于 MBean服务器中。MBean 服务器中的每个MBean实例都通过一个对象名称来唯一地标识就好像是 HashMap 中都每个条目都通过一个键来表示一样干货——ObjectName属性的作用作为标识类型2名称对象是 javax.management.ObjectName 类的实例。对象名称由两部分组成域和一个键值对public class ObjectName implements ComparableObjectName, QueryExp { //javax.management.ObjectName 3键与其值是由等号分割的键值对之间由 分号分割如下面是一个有效的对象名称包含两个键myDomain:typeCar,colorblue4ObjectName 实例也表示在 MBean服务器中搜索 MBean实例的属性模式4.1ObjectName实例可以在域部分或键值对部分使用通配符来表示模式作为模式的 ObjectName实例可以有0个或多个键 【3】 标准MBean1intro 标准MBean 是最简单的MBean类型。要想通过标准MBean来管理一个java对象需要执行以下stepsstep1创建一个接口该接口的命名规范为 java类名MBean后缀如想要管理的java类名为Car则需要创建命名为 CarMBean的接口 step2修改java类让其实现刚刚创建的 CarMBean接口 step3创建一个代理该代理类必须包含一个 MBeanServer实例 step4为MBean创建 ObjectName 实例 step5实例化 MBeanServer类 step6将 MBean注册到 MBeanServer 中 2看个荔枝下面是一个标准MBean的例子JMX可管理的类是Carpublic class Car {private String color red;public String getColor() {return color;}public void setColor(String color) {this.color color;}public void drive() {System.out.println(Baby you can drive my car.);} }2.1修改Car类使其实现CarMBean接口 public interface CarMBean {public String getColor();public void setColor(String color);public void drive(); } public class Car implements CarMBean {private String color red;public String getColor() {return color;}public void setColor(String color) {this.color color;}public void drive() {System.out.println(Baby you can drive my car.);} } 对以上代码的分析Analysis要在接口中声明Car 类中所要提供的所有方法在CarMBean 接口中声明了 Car类的所有方法 2.2给出用来创建标准MBean实例和管理Car 对象的代理类 StandardAgent的定义 public class StandardAgent {private MBeanServer mBeanServer null;public StandardAgent() {mBeanServer MBeanServerFactory.createMBeanServer();}public MBeanServer getMBeanServer() {return mBeanServer;}public ObjectName createObjectName(String name) {ObjectName objectName null;try {objectName new ObjectName(name);} catch (Exception e) {}return objectName;}private void createStandardBean(ObjectName objectName,String managedResourceClassName) {try {mBeanServer.createMBean(managedResourceClassName, objectName);} catch (Exception e) {}}public static void main(String[] args) {StandardAgent agent new StandardAgent(); // 创建标准类型MBean的代理.MBeanServer mBeanServer agent.getMBeanServer(); // 创建MBean服务器String domain mBeanServer.getDefaultDomain(); // 设置域String managedResourceClassName com.tomcat.chapter20.standardmbeantest.Car; // 设置要管理的类的全限定名.ObjectName objectName agent.createObjectName(domain :type managedResourceClassName); // 创建 ObjectName 对象.(用于标识MBean)agent.createStandardBean(objectName, managedResourceClassName); //创建标准类型的MBean.// manage MBeantry {Attribute colorAttribute new Attribute(Color, blue);mBeanServer.setAttribute(objectName, colorAttribute); // 为该MBean设置属性.System.out.println(mBeanServer.getAttribute(objectName, Color)); // 获取该MBean的属性.mBeanServer.invoke(objectName, drive, null, null); // 调用该MBean的drive方法.} catch (Exception e) {e.printStackTrace();}} } 对以上代码的分析Analysis A1StandardAgent类是一个代理类用来实例化 MBean服务器并使用MBean服务器注册CarMBean实例 A2首先要注意的是变量mBeanServerStandardAgent类的构造函数会将一个 MBeanServer实例赋值给变量 MBeanServer。构造函数会调用MBeanServerFactory.createMBeanServer()方法创建一个MBean服务器实例 A3StandardAgent.createObjectName()会根据传入的字符串参数返回一个 ObjectName实例 public ObjectName createObjectName(String name) {ObjectName objectName null;try {objectName new ObjectName(name);} catch (Exception e) {}return objectName;}A4StandardAgent.createStandardMBean()方法会调用 MBeanServer.createMBean()方法createMBean()方法接收托管资源的类名和一个 ObjectName实例该 ObjectName实例唯一地标识了为托管资源创建的MBean实例。createMBean()方法也会将创建的 MBean实例注册到 MBeanServer中由于标准MBean 实例遵循了特定的命名规则因此不需要为 createMBean()方法提供MBean的类名。如果托管资源的 类名是 Car则创建的 MBean 的类名是 CarMBean private void createStandardBean(ObjectName objectName,String managedResourceClassName) {try {mBeanServer.createMBean(managedResourceClassName, objectName);} catch (Exception e) {}} 3StandardAgent.main()方法首先会创建 StandardAgent类的一个实例调用其getMBeanServer()方法以得到 StandardAgent 中对 MBeanServer实例的一次引用StandardAgent agent new StandardAgent();MBeanServer mBeanServer agent.getMBeanServer();4然后它会为 CarMbean实例的创建一个 OBjectgName实例MBeanServer实例的默认域会作为 ObjectName 实例的域使用。一个名为 type 的键会被添加到域后面。键type 的值是托管资源的完全限定名String domain mBeanServer.getDefaultDomain();String managedResourceClassName com.tomcat.chapter20.standardmbeantest.Car;ObjectName objectName agent.createObjectName(domain :type managedResourceClassName);5然后main()方法会调用 createStandardBean()方法并传入对象名称和托管资源的类名agent.createStandardBean(objectName, managedResourceClassName);6接着main()方法就可以通过CarMBean实例来管理Car对象。它会创建一个名为 colorAttribute 的 Attribute类型的对象用来表示 Car类的 Color属性并设置其值为 blue然后它再调用 setAttribute()方法接着它会通过调用 MBeanServer.invoke()方法来嗲用Car.drive()方法// manage MBeantry {Attribute colorAttribute new Attribute(Color, blue);mBeanServer.setAttribute(objectName, colorAttribute);System.out.println(mBeanServer.getAttribute(objectName, Color));mBeanServer.invoke(objectName, drive, null, null);} 7运行结果blue Baby you can drive my car.AttentionA1我们很想知道到底为什么需要使用 JMX 来管理 java对象呢 A2上面的荔枝中我们可以通过 StandardAgent 类来直接访问Car对象了这里的关键问题是可以选择哪些功能需要暴露出来哪些方法需要对外隐藏干货——这里的关键问题是可以选择哪些功能需要暴露出来哪些方法需要对外隐藏 【4】模型MBean1intro相比于标准MBean模型MBean具有更大的灵活性如果不能修改已有的java类那么使用模型MBean是不错 的选择不再需要为可管理的对象修改java类了 2模型MBean和标准MBean的区别干货——模型MBean和标准MBean的区别2.1在使用标准MBean管理资源时需要定义一个接口然后让托管资源实现该接口而使用模型MBean时不需要定义接口相反可以使用 javax.management.modelmbean.ModelMBean 接口来表示模型MBean只需要实现该接口 2.2在JMX 的参考实现中有一个 javax.management.modelmbean.RequiredModelMBean类是ModelMBean接口的默认实现 可以实例化 RequiredModelMBean 类或其子类 3编写一个模型MBean 的最大挑战是 告诉 ModelMBean对象托管资源的哪些属性和方法可以暴露给代理可以通过创建 javax.management.modelmbean.ModelMBeanInfo对象来完成这个任务4javax.management.modelmbean.ModelMBeanInfo对象干货——ModelMBeanInfo对象的作用4.1ModelMBeanInfo对象描述了将会暴露给代理的构造函数属性操作甚至是监听器 5使用 RequiredModelMBean类作为 ModelMBean的实现有两种方法可以将 ModelMBean对象与 ModelMBeanInfo对象相关联method1传入一个 ModelMBeanInfo 对象到 RequiredModelBean 对象的构造函数中 method2调用 RequiredModelMBean 对象的 setModelMBeanInfo()方法并传入一个 ModelMBeanInfo对象 6在创建了 ModelMBean对象后需要调用ModelMBean接口的 setManagedResource()方法将其与托管资源相关联该方法的签名如下public void setManagedResource(Object mr, String mr_type) throws MBeanException, RuntimeOperationsException, InstanceNotFoundException, InvalidTargetObjectTypeException ;【4.1】MBeanInfo 接口与 ModelMBeanInfo接口1javax.management.modelmbean.ModelMBeanInfo 定义源码如下public interface ModelMBeanInfo{ public Descriptor[] getDescriptors(String inDescriptorType)throws MBeanException, RuntimeOperationsException; public void setDescriptors(Descriptor[] inDescriptors)throws MBeanException, RuntimeOperationsException; public Descriptor getDescriptor(String inDescriptorName, String inDescriptorType)throws MBeanException, RuntimeOperationsException; public Descriptor getMBeanDescriptor()throws MBeanException, RuntimeOperationsException; public void setMBeanDescriptor(Descriptor inDescriptor)throws MBeanException, RuntimeOperationsException; public ModelMBeanAttributeInfo getAttribute(String inName)throws MBeanException, RuntimeOperationsException;public ModelMBeanOperationInfo getOperation(String inName)throws MBeanException, RuntimeOperationsException;public ModelMBeanNotificationInfo getNotification(String inName)throws MBeanException, RuntimeOperationsException;public java.lang.Object clone(); public MBeanAttributeInfo[] getAttributes(); public java.lang.String getClassName(); public MBeanConstructorInfo[] getConstructors(); public java.lang.String getDescription(); public MBeanNotificationInfo[] getNotifications(); public MBeanOperationInfo[] getOperations(); }2intro to ModelMBeanInfo接口该接口描述了要通过MOdelMBean 暴露给代理层的构造函数属性方法和监听器干货——ModelMBeanInfo接口的作用JMX提供的默认实现类是ModelMBeanInfoSupport2.1构造函数是 javax.management.modelmbean.ModelMBeanConstructorInfo 类的实例属性是 javax.management.modelmbean.MOdelMBeanAttributeInfo 类的实例方法是 javax.management.modelmbean.ModelMBeanOperationInfo 类的实例监听器是  javax.management.modelmbean.ModelMBeanNotificationInfo 类的实例 2.2JMX 提供了ModelMBeanInfo接口的默认实现即 javax.management.modelmbean.ModelMBeanInfoSupport类 public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { // javax.management.modelmbean.ModelMBeanInfoSupportpublic ModelMBeanInfoSupport(String className,String description,ModelMBeanAttributeInfo[] attributes,ModelMBeanConstructorInfo[] constructors,ModelMBeanOperationInfo[] operations,ModelMBeanNotificationInfo[] notifications) {this(className, description, attributes, constructors,operations, notifications, null);} } 【4.2】ModelMBean实例1看个荔枝 该荔枝展示了如何使用模型MBean管理Car对象。1.1Car 类的源码定义 public class Car {private String color red;public String getColor() {return color;}public void setColor(String color) {this.color color;}public void drive() {System.out.println(Baby you can drive my car.);} } 1.2对于模型MBean不需要像使用标准MBean那样编写一个接口。只需要实例化RequiredMBean类 public class ModelAgent {private String MANAGED_CLASS_NAME com.tomcat.chapter20.modelmbeantest1.Car;private MBeanServer mBeanServer null;public ModelAgent() {mBeanServer MBeanServerFactory.createMBeanServer();}public MBeanServer getMBeanServer() {return mBeanServer;}private ObjectName createObjectName(String name) {ObjectName objectName null;try {objectName new ObjectName(name);} catch (MalformedObjectNameException e) {e.printStackTrace();}return objectName;}private ModelMBean createMBean(ObjectName objectName, String mbeanName) {ModelMBeanInfo mBeanInfo createModelMBeanInfo(objectName, mbeanName);RequiredModelMBean modelMBean null;try {modelMBean new RequiredModelMBean(mBeanInfo);} catch (Exception e) {e.printStackTrace();}return modelMBean;}private ModelMBeanInfo createModelMBeanInfo(ObjectName inMbeanObjectName,String inMbeanName) {ModelMBeanInfo mBeanInfo null;ModelMBeanAttributeInfo[] attributes new ModelMBeanAttributeInfo[1];ModelMBeanOperationInfo[] operations new ModelMBeanOperationInfo[3];try {attributes[0] new ModelMBeanAttributeInfo(Color,java.lang.String, the color., true, true, false, null);operations[0] new ModelMBeanOperationInfo(drive,the drive method, null, void,MBeanOperationInfo.ACTION, null);operations[1] new ModelMBeanOperationInfo(getColor,get color attribute, null, java.lang.String,MBeanOperationInfo.ACTION, null);Descriptor setColorDesc new DescriptorSupport(new String[] {namesetColor, descriptorTypeoperation,class MANAGED_CLASS_NAME, roleoperation });MBeanParameterInfo[] setColorParams new MBeanParameterInfo[] { (new MBeanParameterInfo(new color, java.lang.String, new Color value)) };operations[2] new ModelMBeanOperationInfo(setColor,set Color attribute, setColorParams, void,MBeanOperationInfo.ACTION, setColorDesc);mBeanInfo new ModelMBeanInfoSupport(MANAGED_CLASS_NAME, null,attributes, null, operations, null);} catch (Exception e) {e.printStackTrace();}return mBeanInfo;}public static void main(String[] args) {ModelAgent agent new ModelAgent(); // 创建模型MBean代理. MBeanServer mBeanServer agent.getMBeanServer(); // 创建MBean 服务器.Car car new Car();String domain mBeanServer.getDefaultDomain(); // 创建 域 String managedResourceClassName com.tomcat.chapter20.modelmbeantest1.Car; // 设置要管理的类的全限定名. ObjectName objectName agent.createObjectName(domain :type managedResourceClassName); // 创建 ObjectName 对象.(用于标识MBean) String mBeanName myMBean;ModelMBean modelMBean agent.createMBean(objectName, mBeanName); //创建模型类型的MBean. try {modelMBean.setManagedResource(car, ObjectReference); // 为该模型MBean 设置资源类型mBeanServer.registerMBean(modelMBean, objectName); // 将该模型MBean 注册到 MBean 服务器.} catch (Exception e) {}// manage the beantry {Attribute attribute new Attribute(Color, green);mBeanServer.setAttribute(objectName, attribute); String color (String) mBeanServer.getAttribute(objectName,Color);System.out.println(Color: color); // 设置属性-获取属性-打印属性 attribute new Attribute(Color, blue);mBeanServer.setAttribute(objectName, attribute);color (String) mBeanServer.getAttribute(objectName, Color);System.out.println(Color: color); // 设置属性-获取属性-打印属性 mBeanServer.invoke(objectName, drive, null, null); // 调用MBean 服务器中表示为 objectName的MBean对象的drive方法 } catch (Exception e) {e.printStackTrace();}} } public class Car {public Car() {System.out.println(Car constructor);}private String color red;public String getColor() {return color;}public void setColor(String color) {this.color color;}public void drive() {System.out.println(Baby you can drive my car.);} } 1.3Console info Color:green Color:blue Baby you can drive my car. 【5】 Commons Modeler库1intro该库是Apache 的 Jakarta项目的一部分目的是 使编写模型MBean更加方便实际上最大的帮助是 不需要再写代码创建 ModelMBeanInfo对象了干货——Commons Modeler库的目的2problemsolution2.1problem在前面的荔枝中创建RequiredModelMBean 对象 需要创建一个对象ModelMBeanInfo 对象并将其传递给 RequiredModelMBean 的构造函数 ModelMBeanInfo 对象描述了将要由 MBean实例暴露出的属性和方法 private ModelMBean createMBean(ObjectName objectName, String mbeanName) {ModelMBeanInfo mBeanInfo createModelMBeanInfo(objectName, mbeanName);RequiredModelMBean modelMBean null;try {modelMBean new RequiredModelMBean(mBeanInfo);} //.......2.2solution 使用Commons Modeler 库就不再需要创建 ModelMBeanInfo对象了相反对模型MBean的描述被封装在一个 org.apache.catalina.modeler.ManagedBean对象中。不需要编写代码在MBean中暴露属性和方法。只需要编写一个mbean的描述符文件一个XML文档列出想要创建的 MBean。 3对于每个MBean需要写出MBean类和托管资源类的完全限定名此外还有由  MBean暴露的属性和方法。然后使用 org.apache.commons.modeler.Registry 实例读取这个XML 文档并创建一个 MBeanServer实例在按照mbean描述符文件中的XML 元素创建所有的ManagedBean实例3.1然后调用MAnagedBean.createMBean()方法创建模型MBean。这之后就是普通的流程了。 3.2下面介绍mbean描述符文件的格式 然后讨论Modeler库中的3个重要的类分别是 Registry类ManagedBean类 和 BaseModelMBean类 【5.1】MBean描述符1introMBean描述符是一个XML文档该文档描述了 将会由 MBean服务器管理的模型MBean的实例MBean描述符以下面的头信息开始 1.1mbeans-descriptors根元素 在mbeans-descriptors标签内部是 mbean元素每个mbean标签表示一个模型MBean。mbean元素包含了分别用来表示属性方法构造函数和通知的元素 看个荔枝car-mbean-descriptor.xml 代码定义如下 ?xml version1.0? !DOCTYPE mbeans-descriptors PUBLIC-//Apache Software Foundation//DTD Model MBeans Configuration Filehttp://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtdmbeans-descriptorsmbean namemyMBeanclassNamejavax.management.modelmbean.RequiredModelMBeandescriptionThe ModelMBean that manages our Car objecttypecom.tomcat.chapter20.modelmbeantest2.Carattribute nameColordescriptionThe car colortypejava.lang.String/operation namedrivedescriptiondrive methodimpactACTIONreturnTypevoidparameter namedriver descriptionthe driver parametertypejava.lang.String//operation/mbean/mbeans-descriptors 对以上代码的分析AnalysisA1mbean元素该元素描述一个模型 MBean包含创建对应 ModelMBeanInfo 对象 的信息。mbean元素的定义如下所示 !Element mmean (descriptor?, attribute*, constructor*, notification*, operation*) A1.1mbean元素可以有如下属性property property1name唯一标识模型MBean的名称一般case下会使用相关服务器组件的基类名 property2domain在创建ModelMBean的ObjectName时托管的 bean 创建的 ModelMBean 实例被注册到的 MBean服务器的域名 property3description对该 mbean的 简单描述 property4group组分类的可选名用来选择具有相似MBean 实现类的组 property5type托管资源实现类的完全限定的java类名 property6className实现ModelMBean接口的 java类的完全限定名若该属性未赋值则默认使用 org.apache.commons.modeler.BaseModelMBean类 A2attribute元素使用attribute元素 描述 MBean的 JavaBean属性。有如下属性 property1description该属性的简单描述 property2displayName该属性的显示名称 property3getMethod由 attribute元素表示的属性的 getter()方法 property4is一个布尔值指明该属性是否是一个布尔值是否有 getter()方法默认case下该属性值为false property5name该java bean属性的名称 property6readable一个布尔值指定该属性对管理应用程序来说是否可读该属性值默认为true property7setMethod由 attribute 元素表示的属性的 setter()方法 property8type该属性的完全限定的java类名 property9writeable一个布尔值表明该属性对管理应用程序来说是否可写该属性默认为 true A3operation元素该元素描述了模型 MBean中要暴露给管理应用程序的公共方法它可以有0个或多个 parameter 子元素和如下 的属性 property1description方法的简单描述 property2impact指明方法的影响可选值为ACTION, ACTION-INFO, INFO 或 UNKNOWN property3name公共方法名称 property4returnType方法返回值的完全限定的 java类名 A4parameter元素该元素描述了将要传递给 构造函数或方法的参数有如下属性 property1description该参数的简单描述 property2name参数名 property3type参数的完全限定名的java类名 【5.2】mbena元素示例 1在catalina的mbean-descriptors.xml 文件中声明了一系列模型 MBean该文件包位于 org.apache.catalina.mbeans 包下其源代码如下  mbean nameMBeanFactorytypeorg.apache.catalina.mbeans.MBeanFactorydescriptionFactory for MBeans and corresponding componentsdomainCatalina!-- IMPLEMENTATION NOTE - all of the createXxxxx methods create a new --!-- component and attach it to Catalinas component tree. The return --!-- value is the object name of the corresponding MBean for the new --!-- component. --operation namecreateAccessLoggerValvedescriptionCreate a new AccessLoggerValveimpactACTIONreturnTypejava.lang.Stringparameter nameparentdescriptionMBean Name of the associated parent componenttypejava.lang.String//operation //...... /mbean 对以上代码的分析Analysismbean元素声明了一个模型MBean其唯一标识是 MBeanFactory该MBeanFactory是 org.apache.catalina.mbeans.MBeanFactory 类的一个对象 【5.3】自己编写一个模型MBean类 1intro使用Commons Modeler库需要在 mbean元素的className属性中指明自定义的模型MBean的类型。默认case下Commons Modeler库 使用 org.apache.commons.modeler.BaseModelMBean类 2有两种cases其中可能对 BaseModelMBean类进行扩展 case1需要覆盖托管资源的属性或方法 case2需要添加在托管资源中没有定义的属性或方法 【5.4】Registry类org.apche.commons.modeler.Registry 1该类定了很多方法如下 method1获取javax.management.MBeanServer 类的一个实例所以不再需要调用 javax.management.MBeanServerFactory.createMBeanServer()方法了 method2使用 loadRegistry() 方法读取 MBean 的描述符文件 method3创建一个 ManagedBean 对象用于创建模型 MBean的实例 【5.5】ManagedBean 1introManagedBean 对象描述了一个模型MBean该类用于取代 javax.management.MBeanInfo 对象 【5.6】BaseModelMBean 1org.apache.commons.modeler.BaseModelMBean 类实现了 javax.management.modelmbean.ModelMBean 接口。使用这个类就不需要用 javax.management.modelmbean.RequiredModelMBean类了 2该类用了 resource字段该字段表示该模型 MBean管理的资源 public class BaseModelMBean implements ModelMBean, MBeanRegistration { // org.apache.commons.modeler.BaseModelMBean protected Object resource null; } 【5.7】使用 Modeler库API 1Car类的定义源码 package com.tomcat.chapter20.modelmbeantest2; public class Car {public Car() {System.out.println(Car constructor);}private String color red;public String getColor() {return color;}public void setColor(String color) {this.color color;}public void drive() {System.out.println(Baby you can drive my car.);} } 2使用 Commons Modeler库不需要使用硬编码的方式将托管对象的所有属性和方法都写在代码中。相反可以将他们写在一个 XML文档中作为 MBean 的描述符文件 2.1MBean的描述符文件为 car-mbean-descriptor.xml 文件其代码定义如下 ?xml version1.0? !DOCTYPE mbeans-descriptors PUBLIC-//Apache Software Foundation//DTD Model MBeans Configuration Filehttp://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtdmbeans-descriptorsmbean namemyMBeanclassNamejavax.management.modelmbean.RequiredModelMBeandescriptionThe ModelMBean that manages our Car objecttypecom.tomcat.chapter20.modelmbeantest2.Carattribute nameColordescriptionThe car colortypejava.lang.String/operation namedrivedescriptiondrive methodimpactACTIONreturnTypevoidparameter namedriver descriptionthe driver parametertypejava.lang.String//operation/mbean /mbeans-descriptors 2.2需要一个代理类 ModelAgent.java具体定义如下干货——这里不需要创建ModelMBeanInfo 对象 public class ModelAgent {private Registry registry;private MBeanServer mBeanServer;public ModelAgent() {registry createRegistry();try {mBeanServer Registry.getServer();} catch (Throwable t) {t.printStackTrace(System.out);System.exit(1);}}public MBeanServer getMBeanServer() {return mBeanServer;}public Registry createRegistry() {Registry registry null;try {URL url ModelAgent.class.getResource(/com/tomcat/chapter20/modelmbeantest2/car-mbean-descriptor.xml);InputStream stream url.openStream();Registry.loadRegistry(stream);stream.close();registry Registry.getRegistry();} catch (Throwable t) {System.out.println(t.toString());}return (registry);}public ModelMBean createModelMBean(String mBeanName) throws Exception {ManagedBean managed registry.findManagedBean(mBeanName);if (managed null) {System.out.println(ManagedBean null);return null;}ModelMBean mbean managed.createMBean();ObjectName objectName createObjectName();return mbean;}private ObjectName createObjectName() {ObjectName objectName null;String domain mBeanServer.getDefaultDomain();try {objectName new ObjectName(domain :typeMyCar);} catch (MalformedObjectNameException e) {e.printStackTrace();}return objectName;}public static void main(String[] args) {ModelAgent agent new ModelAgent(); // 创建模型MBean代理.MBeanServer mBeanServer agent.getMBeanServer(); // 创建MBean 服务器.Car car new Car();System.out.println(Creating ObjectName);ObjectName objectName agent.createObjectName(); // 创建 ObjectName作为MBean的标识对象.try {ModelMBean modelMBean agent.createModelMBean(myMBean); // 创建模型MBean. modelMBean.setManagedResource(car, ObjectReference); // 对象引用资源.mBeanServer.registerMBean(modelMBean, objectName); // 注册模型MBean 到 MBean 服务器.(objectName 是标识符)} catch (Exception e) {System.out.println(e.toString());}// manage the beantry {Attribute attribute new Attribute(Color, green); mBeanServer.setAttribute(objectName, attribute); // 创建属性并设置到 MBean服务器中标识为objectName的MBean.String color (String) mBeanServer.getAttribute(objectName,Color);System.out.println(Color: color); // 获取属性并打印.attribute new Attribute(Color, blue);mBeanServer.setAttribute(objectName, attribute);color (String) mBeanServer.getAttribute(objectName, Color);System.out.println(Color: color); // 设置属性-获取属性-打印属性mBeanServer.invoke(objectName, drive, null, null); // 调用MBean 服务器中表示为 objectName的MBean对象的drive方法} catch (Exception e) {e.printStackTrace();}} }// 打印结果. Car constructor Creating ObjectName Color:green Color:blue Baby you can drive my car.span stylefont-family: SimSun; background-color: rgb(255, 255, 255); /span 【6】Catalina中的 MBean1introcatalina在org.apache.catalina.mbeans 包中提供了一系列 MBean类这些 MBean类都直接或间接继承自 org.apache.commons.modeler.BaseModelMBean类2本小姐会讨论tomcat4中的3个最重要的 MBean分别是 ClassNameMBena类 StandardServerMBean类 和 MBeanFactory类干货——tomcat4中最重要的3个MBean【6.1】ClassNameMBena类org.apache.catalina.mbeans.ClassNameMBeanpublic class ClassNameMBean extends BaseModelMBean { // org.apache.catalina.mbeans.ClassNameMBean public ClassNameMBean()throws MBeanException, RuntimeOperationsException {super();}public String getClassName() {return (this.resource.getClass().getName());}}对以上代码的分析Analysis ClassNameMBena类是 BaseModelMBena的子类其只写属性 className 在托管资源中不可见mbeans-descriptors.xml 文件中的很多mbean元素使用该类作为其模型MBean的模型【6.2】StandardServerMBean类public class StandardServerMBean extends BaseModelMBean {private static MBeanServer mserver MBeanUtils.createServer();public StandardServerMBean()throws MBeanException, RuntimeOperationsException {super();}public synchronized void store() throws InstanceNotFoundException,MBeanException, RuntimeOperationsException {Server server ServerFactory.getServer();if (server instanceof StandardServer) {try {((StandardServer) server).store();} catch (Exception e) {throw new MBeanException(e, Error updating conf/server.xml);}}} }对以上代码的分析AnalysisStandardServerMBena类是一种模型MBean继承自 BaseModelMBean类并重写了 托管资源的一个方法【6.3】MBenaFactory类public class MBeanFactory extends BaseModelMBean { //org.apache.catalina.mbeans.MBeanFactory.1introMBenaFactory类的实例是一个工厂对象 用于创建管理 tomcat 中 各种资源的所有模型mbeanMBeanFactory类还提供 了删除这些MBean的方法Attentionorg.apache.catalina.mbeans.MBeanFactory 的源码定义会在文末 po出有兴趣朋友的可以直接跳到文末该类的方法还是比较重要的所以po 之【6.4】MBeanUtilorg.apache.catlaina.mbeans.MBeanUtil1introMBeanUtil类是一个工具类提供了一些静态方法用于创建各种管理 catalina对象的MBean删除MBean以及创建 ObjectName 实例等2看个荔枝 MBeanUtil.createMBean()方法用于创建一个管理 org.apache.catalina.Server 对象的模型MBeanpublic static ModelMBean createMBean(Connector connector) //org.apache.ccatlaina.mbeans.MBeanUtil.createMBean().throws Exception {String mname createManagedName(connector);ManagedBean managed registry.findManagedBean(mname);if (managed null) {Exception e new Exception(ManagedBean is not found with mname);throw new MBeanException(e);}String domain managed.getDomain();if (domain null)domain mserver.getDefaultDomain();ModelMBean mbean managed.createMBean(connector);ObjectName oname createObjectName(domain, connector);mserver.registerMBean(mbean, oname);return (mbean);}【7】创建catalina的MBean1下面介绍一下如何创建 Catalina中的 模型MBean并使用它们来管理 Catalina中的托管资源2在tomcat的配置文件 server.xml 中在 Server元素里面定义了如下所示的Listener元素Server port8005 shutdownSHUTDOWN!-- Security listener. Documentation at /docs/config/listeners.htmlListener classNameorg.apache.catalina.security.SecurityListener /--!--APR library loader. Documentation at /docs/apr.html --Listener classNameorg.apache.catalina.core.AprLifecycleListener SSLEngineon /!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html --Listener classNameorg.apache.catalina.core.JasperListener /!-- Prevent memory leaks due to use of particular java/javax APIs--Listener classNameorg.apache.catalina.core.JreMemoryLeakPreventionListener /Listener classNameorg.apache.catalina.mbeans.GlobalResourcesLifecycleListener /Listener classNameorg.apache.catalina.core.ThreadLocalLeakPreventionListener / //......对以上代码的分析AnalysisA1这里为服务器组件 org.apache.catalina.core.StandardServer 类的实例添加了一个 org.apache.catalina.mbeans.ServerLifecycleListener 类型的监听器。当StandardServer实例启动时它会触发START_EVENT 事件如 StandardServer.start()方法如下所示 public void start() throws LifecycleException { // org.apache.catalina.core.StandardServer.start().// Validate and update our current component stateif (started)throw new LifecycleException(sm.getString(standardServer.start.started));// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);lifecycle.fireLifecycleEvent(START_EVENT, null);started true;// Start our defined Servicessynchronized (services) {for (int i 0; i services.length; i) {if (services[i] instanceof Lifecycle)((Lifecycle) services[i]).start();}}// Notify our interested LifecycleListenerslifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);} A2而当 StandardServer对象关闭时会触发 STOP_EVENT事件如 StandardServer类定义的stop方法 A3而这些时间会执行 ServerLifecycleListener.lifecycleEvnet()方法其源代码定义如下 public void lifecycleEvent(LifecycleEvent event) { //org.apache.catalina.mbeans.ServerLifecycleListener.lifecycleEvent().Lifecycle lifecycle event.getLifecycle();if (Lifecycle.START_EVENT.equals(event.getType())) {if (lifecycle instanceof Server) {// Loading additional MBean descriptorsloadMBeanDescriptors();createMBeans();}// We are embedded.if( lifecycle instanceof Service ) {if( debug 0 )log( Starting embeded lifecycle);try {MBeanFactory factory new MBeanFactory();createMBeans(factory);loadMBeanDescriptors();createMBeans((Service)lifecycle);} catch( Exception ex ) {log(Error registering the service, ex);}}/*// Ignore events from StandardContext objects to avoid// reregistering the contextif (lifecycle instanceof StandardContext)return;createMBeans();*/} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {if (lifecycle instanceof Server) {destroyMBeans();}} else if (Context.RELOAD_EVENT.equals(event.getType())) {// Give context a new handle to the MBean server if the// context has been reloaded since reloading causes the// context to lose its previous handle to the serverif (lifecycle instanceof StandardContext) {// If the context is privileged, give a reference to it// in a servlet context attributeStandardContext context (StandardContext)lifecycle;if (context.getPrivileged()) {context.getServletContext().setAttribute(Globals.MBEAN_REGISTRY_ATTR,MBeanUtils.createRegistry());context.getServletContext().setAttribute(Globals.MBEAN_SERVER_ATTR,MBeanUtils.createServer());}}}} 3在Catalina中createMBeans()方法用来创建所有的MBean实例。该方法首先会创建 MBeanFactory类的一个实例也是一个 模型 MBean实例方法源码定义如下protected void createMBeans() { // org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans().try {MBeanFactory factory new MBeanFactory();createMBeans(factory);createMBeans(ServerFactory.getServer());}//......}对以上代码的分析AnalysisA1第一个 createMBeans方法会使用MBeanUtil类为 MBeanFactory实例创建一个 ObjectName然后将其注册到 MBean服务器中 protected void createMBeans(MBeanFactory factory) throws Exception {// Create the MBean for the MBeanFactoryif (debug 2)log(Creating MBean for MBeanFactory factory);MBeanUtils.createMBean(factory);}A2第二个 createMBeans方法该方法接收一个 org.apache.catalina.Server 对象为其创建一个模型 MBean protected void createMBeans(Server server) throws Exception {// Create the MBean for the Server itselfif (debug 2)log(Creating MBean for Server server);MBeanUtils.createMBean(server);if (server instanceof StandardServer) {((StandardServer) server).addPropertyChangeListener(this);}// Create the MBeans for the global NamingResources (if any)NamingResources resources server.getGlobalNamingResources();if (resources ! null) {createMBeans(resources);}// Create the MBeans for each child ServiceService services[] server.findServices();for (int i 0; i services.length; i) {// FIXME - Warp object hierarchy not currently supportedif (services[i].getContainer().getClass().getName().equals(org.apache.catalina.connector.warp.WarpEngine)) {if (debug 1) {log(Skipping MBean for Service services[i]);}continue;}createMBeans(services[i]);}} Attention上述createMbeans(Server server)方法调用for 循环中下面的语句遍历 StandardServer实例中所有的Service对象for (int i 0; i services.length; i) {// FIXME - Warp object hierarchy not currently supportedif (services[i].getContainer().getClass().getName().equals(org.apache.catalina.connector.warp.WarpEngine)) {if (debug 1) {log(Skipping MBean for Service services[i]);}continue;}createMBeans(services[i]); //highlight line.}对createMBeans(services[i]) 方法的分析Analysis A1该方法为每个Service对象创建 MBean然后为每个Service对象中所有的连接器和Engine对象调用createMBean() 方法 创建 MBean实例 protected void createMBeans(Service service) throws Exception {// Create the MBean for the Service itselfif (debug 2)log(Creating MBean for Service service);MBeanUtils.createMBean(service);if (service instanceof StandardService) {((StandardService) service).addPropertyChangeListener(this);}// Create the MBeans for the corresponding ConnectorsConnector connectors[] service.findConnectors();for (int j 0; j connectors.length; j) {createMBeans(connectors[j]);}// Create the MBean for the associated Engine and friendsEngine engine (Engine) service.getContainer();if (engine ! null) {createMBeans(engine);}} A2createMBean(engine) 会调用 createMBean(Engine engine) 方法为每个Host实例创建MBean protected void createMBeans(Engine engine) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans().// Create the MBean for the Engine itselfif (debug 2) {log(Creating MBean for Engine engine);}MBeanUtils.createMBean(engine);engine.addContainerListener(this);if (engine instanceof StandardEngine) {((StandardEngine) engine).addPropertyChangeListener(this);} //....... A3createMBean(host) 会调用 createMBean(Host host) 方法为每个Context实例创建MBean protected void createMBeans(Host host) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Host host).//......MBeanUtils.createMBean(host);//......Container contexts[] host.findChildren();for (int k 0; k contexts.length; k) {createMBeans((Context) contexts[k]);}//...... } A4createMBean(Context context) 方法的实现如下所示 protected void createMBeans(Context context) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Context context).//.......MBeanUtils.createMBean(context);context.addContainerListener(this);if (context instanceof StandardContext) {((StandardContext) context).addPropertyChangeListener(this);((StandardContext) context).addLifecycleListener(this);}if (context.getPrivileged()) {context.getServletContext().setAttribute(Globals.MBEAN_REGISTRY_ATTR,MBeanUtils.createRegistry());context.getServletContext().setAttribute(Globals.MBEAN_SERVER_ATTR,MBeanUtils.createServer());}//...... } 对以上代码的分析AnalysisA1如果Context实例的 privileged 属性为true则会为 web 应用程序添加两个属性并将其存储在 ServletContext对象中两个属性的键名分别是 Globals.MBEAN_REGISTRY_ATTR 和 Globals.MBEAN_SERVER_ATTR 定义如下 public static final String MBEAN_REGISTRY_ATTR org.apache.catalina.Registry;public static final String MBEAN_SERVER_ATTR org.apache.catalina.MBeanServer;A2MBeanUtils.createRegistry() 方法返回一个 Registry实例而createServer()方法返回一个 javax.management.MBeanServer 实例。Catalina中所有的MBean 都注册于 MBeanServer实例中 A3换句话说当privilegedtrue时才可以从一个web 应用程序中获取 Registry 类 和 MBeanServer类的对象 【8】 应用程序1intro该应用程序是用来管理 tomcat 的web 应用程序。虽然它很simple但已足够说明如何使用 Catalina暴露出的MBean。可以列出 Catalina 中所有 ObjectName 实例以及当前正在运行的所有 Context实例并删除其中任意一个2利用JMX 管理tomcat 中bean 的应用程序构造step1为该web 应用程序创建描述符文件如下所示该文件放到 %CATALINA_HOME%/webapps 目录下 !-- myadmin.xml -- ?xml version1.0 encodingUTF-8? Context path/myadmin docBase./webapps/myadmin debug8privilegedtrue reloadabletrue /Context AttentionContext元素的privileged 必须为 truedocBase属性指定了web 应用程序的文件路径 step2该web 应用程序包含一个servlet代码如下 public class MyAdminServlet extends HttpServlet{private Registry registry;private MBeanServer mBeanServer;Overridepublic void init() throws ServletException {registry (Registry)getServletContext().getAttribute(org.apache.catalina.Registry);if(registry null) {System.out.println(registry not available);return ;}mBeanServer (MBeanServer)getServletContext().getAttribute(org.apache.catalina.MBeanServer);if(mBeanServer null) {System.out.println(mBeanServer not available);return ;}}Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType(text/html);PrintWriter out response.getWriter();if(registry null) {System.out.println(registry not available);return ;}out.println(htmlhead/headbody);String action request.getParameter(action);if(listAllManagedBeans.equals(action)) {listAllManagedBeans(out);} else if(listAllContexts.equals(action)) {listAllContexts(out);}else if (removeContext.equals(action)) {String contextObjectName request.getParameter(contextObjectName);removeContext(contextObjectName, out);} else {out.println(invalid commands.);}out.println(/body/html);}private void listAllManagedBeans(PrintWriter out) {String[] managedBeanNames registry.findManagedBeans();for (int i 0; i managedBeanNames.length; i) {out.print(managedBeanNames[i] br/);}}private void listAllContexts(PrintWriter out) {try {ObjectName objName new ObjectName(Catalina:typeContext,*);Set set mBeanServer.queryNames(objName, null);Iterator it set.iterator();while(it.hasNext()) {ObjectName obj (ObjectName)it.next();out.print(obj a href?actionremoveContextcontextObjectName URLEncoder.encode(obj.toString(), UTF-8) remove/abr/);}} catch (Exception e) {out.print(e.toString());}}private void removeContext(String contextObjectName, PrintWriter out) {try {ObjectName mBeanFactoryOBjectName new ObjectName(Catalina:typeMBeanFactory);if(mBeanFactoryOBjectName ! null) {String operation removeContext;String[] params new String[1];params[0] contextObjectName;String signature[] {java.lang.String};try {mBeanServer.invoke(mBeanFactoryOBjectName, operation, params, signature);out.print(context removed);} catch (Exception e) {out.print(e.toString());}}} catch (Exception e) {}} } step3需要一个应用程序部署描述符文件。web.xml 代码如下 ?xml version1.0 encodingISO-8859-1? !--Licensed to the Apache Software Foundation (ASF) under one or morecontributor license agreements. See the NOTICE file distributed withthis work for additional information regarding copyright ownership.The ASF licenses this file to You under the Apache License, Version 2.0(the License); you may not use this file except in compliance withthe License. You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an AS IS BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License. -- web-app xmlnshttp://java.sun.com/xml/ns/javaeexmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsdversion3.0metadata-completetrueservletservlet-namemyAdmin/servlet-nameservlet-classmyadmin.MyAdminServlet/servlet-class/servletservlet-mappingservlet-namemyAdmin/servlet-nameurl-pattern/myAdmin/url-pattern/servlet-mapping /web-app 3访问效果
http://www.zqtcl.cn/news/504112/

相关文章:

  • h5做网站用什么框架seo推广计划
  • 亿企搜网站建设百度网盘怎么领取免费空间
  • 天津网站排名提升如何用h5做网站
  • 外贸公司有必要建设网站吗赣州做网站哪家好
  • 功能型网站设计深圳网站优化效果
  • 郑州定制网站开发规模以上工业企业总产值
  • 锡林浩特市长安网站 建设初步方案廊坊百度推广排名优化
  • 搭建论坛网站的流程企业网络推广软件
  • 中国化工建设网站家居装修设计
  • 铜陵公司做网站大淘客网站建设app
  • 网站面包屑导航织梦做网站的教程
  • 建湖网站建设价格小程序商城哪个平台好
  • 网站域名 被别人备案买房的人都哭了吧
  • 自己做网站 套模板工具磨床东莞网站建设
  • 怎么上传图片到公司网站在深圳注册公司需要什么资料
  • 网站建设的公司哪家好用一段话来解释网站建设
  • 没有文字的网站怎么优化wordpress自定义文章类型模板
  • 东营网站设计制作网站建设匠人匠心科技
  • 海外如何淘宝网站建设2022新闻大事件摘抄
  • 仿win8 网站淘宝客网站开发视频教程
  • 宣威做网站建设的公司哈尔滨网站建设公司名字
  • 学网页设计在哪学关键词优化公司前十排名
  • 菏泽定制网站建设推广无固定ip 建设网站
  • wordpress网站制作教程视频百度云域名购买
  • 软件最全网站株洲网站排名优化价格
  • 购物便宜的网站有哪些家居企业网站建设讯息
  • 美橙网站产品详情深圳做网站的公司哪个好
  • 江苏省建设注册中心网站平面设计要素
  • 厦门网站建设_策划公司
  • 惠州建网站服务网站建设价格是哪些方面决定的