log4j自定义jdbc appender,数据源

时间:2014-09-04 16:20:22

标签: spring log4j applicationcontext

要在我的log4j appender中使用数据源,我编写了一个自定义appender。 appender试图将数据源作为spring bean。但是,appender无法获取bean。我使用的技术堆栈是:mybatis,tomcat和spring。

我的log4j文件如下所示:

#configuring the requestinterceptor  
log4j.category.com.db.wscis.core.web.interceptor=INFO, sql
log4j.appender.sql=com.db.wscis.core.util.appender.CustomJDBCAppender
log4j.appender.sql.sql=INSERT INTO LOGS VALUES ('%x', current_timestamp ,'%C','%p','%m')
log4j.appender.sql.layout=org.apache.log4j.PatternLayout

自定义appender的代码如下:

public class CustomJDBCAppender extends org.apache.log4j.jdbc.JDBCAppender {

 protected java.sql.Connection getConnection() throws java.sql.SQLException {

         if(connection == null) {
             org.springframework.jdbc.datasource.DataSourceTransactionManager dstm = (org.springframework.jdbc.datasource.DataSourceTransactionManager) ExternalBeanFactory.getBean("txManager");
             if(dstm==null) throw new java.sql.SQLException("dstm is null");
             System.out.println("here");
             connection = DataSourceUtils.getConnection(dstm.getDataSource());
             return connection;
         } else{
             return connection;
         }
     }

    /* protected void execute(String sql) throws java.sql.SQLException {

         Connection con = null;
         Statement stmt = null;

         try {
             con = getConnection();
             stmt = con.createStatement();
             stmt.executeUpdate(sql);
             con.commit();
         } catch (SQLException e) {
            if (stmt != null)
                 stmt.close();
            closeConnection(con);
            throw e;
         } 
       }
     */
     protected void closeConnection() throws java.sql.SQLException {
             if (connection != null && !connection.isClosed())
                   connection.close();
     }
}

外部Bean工厂类看起来像这样:

/* 
 */    
package com.db.wscis.core.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

public class ExternalBeanFactory implements BeanFactoryAware {

    /**
     * Bean factory instance.
     */
    private static BeanFactory beanFactory;

    /**
     * Sets beanfactory.
     * 
     * @param beanFactory
     *            BeanFactory object
     * 
     * @see org.springframework.beans.factory.BeanFactoryAware#
     *      setBeanFactory(org.springframework.beans.factory.BeanFactory)
     * @exception BeansException
     *                if failed to set factory
     */
    public final void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    /**
     * DO NOT use this method in the application classes. This is meant to be
     * used by the framework level classes ONLY!!!!
     * 
     * Finds from bean from the factory.
     * 
     * @param beanName
     *            Name of the bean
     * @return bean object
     */
    @Deprecated
    public static final Object getBean(final String beanName) {
    //  if(beanFactory==null) System.out.println("Bean factory is null");
        return beanFactory.getBean(beanName);
    }

    public final Object getBeanInstance(final String beanName) {
        return beanFactory.getBean(beanName);
    }
}

现在,当tomcat服务器启动时,我的猜测是它尝试初始化log4j。因此,它在自定义appender中调用getConnection方法。此inturn调用ExernalFactory.getBean(),但是,外部BeanFactory中的beanfactory属性尚未初始化。
错误堆栈跟踪如下:

SEVERE: Error configuring application listener of class com.db.wscis.core.web.context.FWContextLoaderLis
java.lang.NullPointerException
        at com.db.wscis.core.util.ExternalBeanFactory.getBean(ExternalBeanFactory.java:64)
        at com.db.wscis.core.util.appender.CustomJDBCAppender.getConnection(CustomJDBCAppender.java:27)
        at org.apache.log4j.jdbc.JDBCAppender.execute(JDBCAppender.java:215)
        at org.apache.log4j.jdbc.JDBCAppender.flushBuffer(JDBCAppender.java:289)
        at org.apache.log4j.jdbc.JDBCAppender.append(JDBCAppender.java:186)
        at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
        at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.
        at org.apache.log4j.Category.callAppenders(Category.java:206)
        at org.apache.log4j.Category.forcedLog(Category.java:391)
        at org.apache.log4j.Category.log(Category.java:856)
        at org.apache.commons.logging.impl.Log4JLogger.info(Log4JLogger.java:176)
        at com.db.wscis.core.web.context.FWContextLoaderListener.<init>(FWContextLoaderListener.java:34)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.j
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at java.lang.Class.newInstance(Class.java:374)
        at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:140)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4888)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1073)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
        at java.util.concurrent.FutureTask.run(FutureTask.java:166)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:724)

请告诉我我做错了什么以及如何在appender类中获取数据源bean实例。

1 个答案:

答案 0 :(得分:0)

我设法解决了这个问题:

因此,我的数据源bean是在应用程序上下文中声明的。另一方面,我的外部bean工厂在根上下文中声明。现在,根上下文中的bean无法在应用程序Context中看到bean。因此,我的External Bean Factory中的beanfactory属性从未被初始化。我花了一些时间才弄明白,但谢天谢地,它有效!