P6Spy source code analysis - Connection acquisition, statement timeout log printing

P6Spy use: http://donald-draper.iteye.com/blog/2319646
P6Spy source code analysis-property file loading: http://donald-draper.iteye.com/admin/blogs/2319851
P6Spy source code analysis-Connection acquisition, Log printing: http://donald-draper.iteye.com/admin/blogs/2319873
This sentence is used when using P6Spy. Let's look at the connotation of this sentence:
P6DataSource p6DSource = new P6DataSource(cpDSource)
// p6DSource = new P6DataSource(cpDSource)
public class P6DataSource extends P6Base
    implements DataSource, Referenceable, Serializable
{
    //source is the data source c3p0 or Druid passed in by constructing
    public P6DataSource(DataSource source)
    {
        rds = source;
    }
    //Initialize the driver and log module
    public static void initMethod()
    {
        P6SpyDriverCore.initMethod((com.p6spy.engine.spy.P6SpyDriver.class).getName());
    }
    //Get Connection
     public Connection getConnection()
        throws SQLException
    {
        if(rds == null)
            bindDataSource();
        return P6SpyDriverCore.wrapConnection(rds.getConnection());
    }
    protected DataSource rds;
    protected String rdsName;
    //Call the initialization method through the static statement block
    static
    {
        initMethod();
    }
}

Timeout log line analysis:
P6DataSource, the getConnection method gets the connection through P6SpyDriverCore.wrapConnection(rds.getConnection());
let's see what the wrapConnection method of P6SpyDriverCore does
public abstract class P6SpyDriverCore
    implements Driver
{
    public static synchronized void initMethod(String spydriver)
    {
        if(initialized)
            return;
        String path = P6SpyProperties.getPropertiesPath();
        if(path == null)
        {
            foundSpyProperties = false;
            return;
        }
        foundSpyProperties = true;
	//Initialize the spy.properties property file
        P6SpyProperties properties = new P6SpyProperties();
        P6SpyOptions coreOptions = new P6SpyOptions();
        OptionReloader.add(coreOptions, properties);
        String className = "no class";
        String classType = "driver";
        try
        {
	    // realdriver
            ArrayList driverNames = null;
	    //log module
            ArrayList modules = null;
	    //get driver name
            driverNames = P6SpyOptions.allDriverNames ();
	    //Get all log modules
            modules = P6SpyOptions.allModules();
            boolean hasModules = modules.size() > 0;
            Iterator i = null;
            classType = "driver";
            Driver realDriver;
            for(i = driverNames.iterator(); i.hasNext(); P6LogQuery.logDebug("Registered driver: " + className + ", realdriver: " + realDriver))
            {
                P6SpyDriver spy = null;
                if(hasModules)
                {
                    spy = new P6SpyDriver();
                    DriverManager.registerDriver(spy);
                }
                className = (String)i.next();
                deregister(className);
                realDriver = (Driver)P6Util.forName(className).newInstance();
                if(P6SpyOptions.getDeregisterDrivers())
		    //Register the driver realdriver=com.mysql.jdbc.Driver
                    DriverManager.registerDriver (realDriver);
                if(hasModules)
                {
                    spy.setPassthru (realDriver);
                    realDrivers.add (realDriver);
                }
            }

            if(hasModules)
            {
                factories = new ArrayList();
                classType = "factory";
                com.p6spy.engine.common.P6Options options;
                for(i = modules.iterator(); i.hasNext(); P6LogQuery.logDebug("Registered factory: " + className + " with options: " + options))
                {
                    className = (String)i.next();
		    //module.log=com.p6spy.engine.logging.P6LogFactory
                    //module.outage=com.p6spy.engine.outage.P6OutageFactory
                    P6Factory factory = (P6Factory) P6Util.forName (className) .newInstance ();
                    factories.add(factory);
                    options = factory.getOptions();
                    if(options != null)
                        OptionReloader.add(options, properties);
                }

            }
            initialized = true;
            for(Enumeration e = DriverManager.getDrivers(); e.hasMoreElements(); P6LogQuery.logDebug("Driver manager reporting driver registered: " + e.nextElement()));
        }
        catch(Exception e)
        {
            String err = "Error registering " + classType + "  [" + className + "]\nCaused By: " + e.toString();
            P6LogQuery.logError(err);
            throw new P6DriverNotFoundError(err);
        }
    }
//The getConnection method of P6DataSource uses the wrapConnection(Connection realConnection) method of P6SpyDriverCore
public static Connection wrapConnection(Connection realConnection)
        throws SQLException
    {
        Connection con = realConnection;
        if(factories != null)
        {
            for(Iterator it = factories.iterator(); it.hasNext();)
            {
                P6Factory factory = (P6Factory)it.next();
		//Here is the key point, here is to get the connection through P6Factory, P6SpyDriverCore
		//In the initialization initMethod has P6LogFactory, P6OutageFactory
		//module.log=com.p6spy.engine.logging.P6LogFactory
                //module.outage=com.p6spy.engine.outage.P6OutageFactory
                con = factory.getConnection(con);
            }

        }
        return con;
    }
    protected Driver passthru;
    protected static boolean initialized = false;
    protected static ArrayList factories;
    protected static ArrayList realDrivers = new ArrayList();
    protected static boolean foundSpyProperties;
}

This sentence is very important: con = factory.getConnection(con), this factory is actually P6LogFactory or P6OutageFactory
Let's take a look at the getConnection() method of P6OutageFactory
public class P6OutageFactory extends P6CoreFactory
{ //return P6OutageConnection
public Connection getConnection(Connection conn)
        throws SQLException
    {
        return new P6OutageConnection(this, conn);
    }
    //return P6OutagePreparedStatement
    public PreparedStatement getPreparedStatement(PreparedStatement real, P6Connection conn, String p0)
        throws SQLException
    {
        return new P6OutagePreparedStatement(this, real, conn, p0);
    }
}

Look at P6OutageConnection again
public class P6OutageConnection extends P6Connection
    implements Connection
{
   //submit
    public void commit()
        throws SQLException
    {
        long startTime = System.currentTimeMillis();
	//outagedetection=true
        if(P6OutageOptions.getOutageDetection())
	//P6OutageDetector, register the statement behavior commit event
            P6OutageDetector.getInstance().registerInvocation(this, startTime, "commit", "", "");
        try
        {
            passthru.commit();
        }
        finally
        {
            if(P6OutageOptions.getOutageDetection())
                P6OutageDetector.getInstance().unregisterInvocation(this);
        }
    }
}

Look at P6Connection again
public class P6Connection extends P6Base
    implements Connection
{
   Get the precompiled Statement and see if this is the familiar JDBC Connection.prepareStatement(String sql)
public PreparedStatement prepareStatement(String p0)
        throws SQLException
    {
        The actual method used here is the getPreparedStatement method of P6OutageFactory, which returns P6OutagePreparedStatement
        return getP6Factory().getPreparedStatement(passthru.prepareStatement(p0), this, p0);
    }
}

Look at P6OutagePreparedStatement again
public class P6OutagePreparedStatement extends P6PreparedStatement
    implements PreparedStatement
{

    public boolean execute()
        throws SQLException
    {
        long startTime = System.currentTimeMillis();
        //outagedetection=true
        if(P6OutageOptions.getOutageDetection())
	    //Register the statement to P6OutageDetector (statement timeout detector)
            P6OutageDetector.getInstance().registerInvocation(this, startTime, "statement", preparedQuery, getQueryFromPreparedStatement());
        boolean flag;
        try
        {
            flag = prepStmtPassthru.execute();
        }
        finally
        {
	    //outagedetection=true
            if(P6OutageOptions.getOutageDetection())
	        //When the statement is executed, remove the statement from P6OutageDetector (statement timeout detector)
                P6OutageDetector.getInstance().unregisterInvocation(this);
        }
        return flag;
    }
}

Look at P6OutageOptions again
//timeout property configuration
//outagedetection=true
//outagedetectioninterval=5
public class P6OutageOptions extends P6Options
{
    public static boolean getOutageDetection()
    {
        return outageDetection;
    }

    public static void setOutageDetection(String _outagedetection)
    {
        outageDetection = P6Util.isTrue(_outagedetection, false);
    }

    public static long getOutageDetectionInterval()
    {
        return outageDetectionInterval;
    }

    public static long getOutageDetectionIntervalMS()
    {
        return outageMs;
    }

    public static void setOutageDetectionInterval(String _outagedetectioninterval)
    {
        outageDetectionInterval = P6Util.parseLong(_outagedetectioninterval, -1L);
        outageMs = outageDetectionInterval * 1000L;
    }

    protected static boolean outageDetection;
    protected static long outageDetectionInterval;
    protected static long outageMs;
}

Look at P6OutageDetector (statement timeout detector)
// is actually a thread
public class P6OutageDetector
    implements Runnable
{

    protected P6OutageDetector()
    {
        pendingMessages = null;
        haltThread = false;
        pendingMessages = new Hashtable();
        P6LogQuery.logDebug("P6Spy - P6OutageDetector has been invoked.");
        P6LogQuery.logDebug("P6Spy - P6OutageOptions.getOutageDetectionIntervalMS() = " + P6OutageOptions.getOutageDetectionIntervalMS());
    }
    //Singleton mode to get the detector instance
    public static synchronized P6OutageDetector getInstance()
    {
        if(instance == null)
        {
            instance = new P6OutageDetector();
            ThreadGroup group = new ThreadGroup("P6SpyThreadGroup");
	    // put it before running
            group.setDaemon(true);
            Thread outageThread = new Thread(group, instance, "P6SpyOutageThread");
            outageThread.start();
        }
        return instance;
    }

    public void run()
    {
        while(!haltThread)
        {
            detectOutage();
            try
            {
	        //Sleep outagedetectioninterval=5 seconds
                Thread.sleep(P6OutageOptions.getOutageDetectionIntervalMS());
            }
            catch(Exception e) { }
        }
    }

    public void shutdown()
    {
        haltThread = true;
    }
    //Register the statement to the detector
    public void registerInvocation(Object jdbcObject, long startTime, String category, String ps, String sql)
    {
	//pendingMessages is actually a HashMap, private Hashtable pendingMessages;
        pendingMessages.put(jdbcObject, new InvocationInfo(startTime, category, ps, sql));
    }
    // remove the statement from the detector
    public void unregisterInvocation(Object jdbcObject)
    {
        pendingMessages.remove(jdbcObject);
    }
    //Detect if there is a timeout statement
    private void detectOutage()
    {
        int listSize = pendingMessages.size();
        if(listSize == 0)
            return;
        P6LogQuery.logDebug("P6Spy - detectOutage.pendingMessage.size = " + listSize);
        long currentTime = System.currentTimeMillis();
        long threshold = P6OutageOptions.getOutageDetectionIntervalMS();
        Set keys = pendingMessages.keySet();
        for(Iterator keyIter = keys.iterator(); keyIter.hasNext();)
        {
	    
            InvocationInfo ii = (InvocationInfo)pendingMessages.get(keyIter.next());
	   / / Determine whether the statement has timed out
            if(ii != null && currentTime - ii.startTime > threshold)
            {
		// print log
                P6LogQuery.logDebug("P6Spy - statement exceeded threshold - check log.");
                logOutage(ii);
            }
        }

    }
    // print log
    private void logOutage(InvocationInfo ii)
    {
        P6LogQuery.logElapsed(-1, ii.startTime, "OUTAGE", ii.preparedStmt, ii.sql);
    }

    private Hashtable pendingMessages;
    private boolean haltThread;
    private static P6OutageDetector instance = null;
    private static final boolean debug = true;

}

The P6LogQuery class will not be analyzed here. It has been said before.
Summary :
Through the above analysis, I believe that everyone has a
preliminary . The main points, static statement blocks, initialization classes, Use the factory mode to obtain the connection, the
singleton mode to obtain the detector, and the log printing is mainly embedded by encapsulating the jdbc statement.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327100900&siteId=291194637