使用JMX跟踪JDBC调用
一种编写跟踪代码并提供一个用户界面来查看SQL的简单方法是编写一个JSP、一个Servlet以及一个Java Bean或对象。我们将展示bean/POJO的全部细节,而省去用户界面/控制器方面的大多数细节,因为大多数WebLogic开发人员对此已有很深的了解。注意,无需修改任何部署描述符、数据库连接池或数据源来实现跟踪,所有对应用程序的更改将在运行时进行。
步骤1
首先我们将创建一个名为MyTracerBean.java的类,并导入所需的WebLogic JMX包和类。
import javax.naming.Context; import weblogic.jndi.Environment; import weblogic.management.MBeanHome; import weblogic.management.configuration.JDBCConnectionPoolMBean; import weblogic.management.runtime.JDBCStatementProfile; import weblogic.management.runtime.JDBCConnectionPoolRuntimeMBean; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.naming.NamingException;
这些类均位于weblogic.jar中,因此不需要向WebLogic类路径添加任何JAR或类。
步骤2
接下来我们将编写一个获取MBeanHome的方法。
private MBeanHome getMBeanHome() { //URL to the serve whose JDBC activity we are tracing String url = "t3://localhost:7001"; String username = "mywlconsoleuname"; String password = "mywlconsolepsswd"; //The MBeanHome will allow us to //retrieve the MBeans related to JDBC statement tracing MBeanHome home = null; try { //We'll need the environment so that we can //retrieve the initial context Environment env = new Environment(); env.setProviderUrl(url); env.setSecurityPrincipal(username); env.setSecurityCredentials(password Context ctx = env.getInitialContext(); //Retrieving the MBeanHome interface for the server with //the url t3://localhost:7001 home =(MBeanHome)ctx.lookup(MBeanHome.LOCAL_JNDI_NAME); } catch (NamingException ne) { System.out.println("Error getting MBeanHome " + ne); } return home; }对于最简单的情形:管理服务器也驻留了我们要跟踪的JDBC应用程序,上述代码完全可行;但是对于管理服务器独立于托管服务器,并且涉及到几个独立JVM的情形,我们需要获得管理MBeans home而不是本地MBeans home。二者的区别在于,本地home只为单个服务器提供Mbean,而管理home则为管理服务器所管理的所有服务器提供MBean。为了获得管理MBeans home而不是本地MBeans home,可以将上述代码中的LOCAL_JNDI_NAME替换为ADMIN_JNDI_NAME。
public void configureJDBCAuditing(boolean isOn) { try { MBeanHome home = getMBeanHome(); //Retreive the bean to help us configure the Pool JDBCConnectionPoolMBean mConfigBean = (JDBCConnectionPoolMBean)home.getConfigurationMBean("MyPool","JDBCConnectionPoolConfig"); mConfigBean.setSqlStmtProfilingEnabled(isOn); mConfigBean.setSqlStmtParamLoggingEnabled(isOn); } catch (InvalidAttributeValueException iave) { System.out.println("Invalid attribute while configuring tracing " + iave); } catch (InstanceNotFoundException infe) { System.out.println("Instance not found while configuring tracing " + infe); } }在上述代码中,我们还告知连接池我们希望查看传入SQL语句中的参数。这会增加跟踪的开销,但是它可以为我们提供一些有价值的信息。
/** Pass in -1 to get all profiles */ public JDBCStatementProfile[] getProfiles(int maxProfiles) { JDBCStatementProfile[] profiles = null; try { MBeanHome home = getMBeanHome(); JDBCConnectionPoolRuntimeMBean mbean = (JDBCConnectionPoolRuntimeMBean)home.getRuntimeMBean("MyPool ","JDBCConnectionPoolRuntime"); int numProfiles = mbean.getStatementProfileCount(); int profilesIndex = 0; //figure out index to start at and how many we want if (maxProfiles != -1) { profilesIndex = numProfiles - maxProfiles; }else { maxProfiles = numProfiles; } profiles =mbean.getStatementProfiles(profilesIndex,maxProfiles); } catch (InstanceNotFoundException infe) { System.out.println("Problem retrieving jdbc profiles " + infe); } return profiles; }JDBCConnectionPoolRuntimeMBean的 getStatementProfiles方法在WebLogic 8.1 API文档中没有提及,尽管它曾在WebLogic 6.1文档中出现。不过这看起来是个错误,因为在WebLogic 8.1中该方法是可用的,并且WebLogic 8.1还修复了方法中的一个bug(CR094729,参见 http://e-docs.bea.com/wls/docs81/notes/resolved_sp01.html),这意味着WebLogic 8.1是打算包含该方法的。
public void reset() { MBeanHome home = getMBeanHome(); try { JDBCConnectionPoolRuntimeMBean mbean = (JDBCConnectionPoolRuntimeMBean)home.getRuntimeMBean("MyPool ","JDBCConnectionPoolRuntime"); //Remove everything from the cache mbean.resetStatementProfile(); } catch (InstanceNotFoundException infe) { System.out.println("Problem while resetting JDBC profiles " + infe); } }步骤6
MyTracerBean myTracer = new MyTracerBean(); //In this case we want the 100 most recently executed statements JDBCStatementProfile[] profiles = myTracer.getProfiles(100); //Doing the looping so that the most recent statements information is //retrieved first for (int i=profiles.length-1;i>-1;i--) { //Getting the number of parameters passed into the current //statement int paramCount = profiles[i].getParameterCount(); //Format the start and end time for the current statement SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm:ss:SS aaa"); String startTime=simpleDateFormat.format(new Date(profiles[i].getStartTime())); String endTime=simpleDateFormat.format(new Date(profiles[i].getStopTime())); //Append the parameters together in order to display them StringBuffer paramsBuffer = new StringBuffer(); if (paramCount < 1) { paramsBuffer.append("None"); } else { for (int j=0;j<paramCount;j++) { paramsBuffer.append(profiles[i].getParameter(j)); paramsBuffer.append(" "); } } String statementTxt = profiles[i].getStatementText(); String paramsTxt = paramsBuffer.toString(); String timeTaken = profiles[i].getTimeTaken() //Then use statementTxt, paramsTxt, timeTaken, startTime, endTime // etc to show the statement details in a UI }
展望WebLogic JMX的前景
在撰写本文时,刚刚发布的WebLogic 9.0支持的是JMX 1.2而不是WebLogic 8.1及以前版本一直支持的JMX 1.0。响应JMX规范的变化,9.0中的WebLogic JMX API有了相当大的变化,清单1中的代码可能会引起不支持的警告。当升级至9.0时,应当用JDBCDataSourceRuntimeMBean替换JDBCConnectionPoolRuntimeMBean。不过,在撰写本文时,绝大多数运行在WebLogic上的遗留应用程序还没有使用WebLogic Server 9.0,而且很可能在相当长的一段时间内不会使用9.0。
原文出处: Custom Debugging with WebLogic JMX http://wldj.sys-con.com/read/138275.htm
作者简介 | |
Salma Saad在International Survey Research公司工作,她负责ISR的完善且高可用的全球调查报告网站,在Java及相关技术领域拥有接近十年的专业经验。 |