log4j自定义jdbc应用器,数据源[英] log4j custom jdbc appender , datasource

本文是小编为大家收集整理的关于log4j自定义jdbc应用器,数据源的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

要在我的log4j appender中使用数据源,我写了一个自定义的appender. Appender试图将数据源视为弹簧豆.但是,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();
     }
}

外部豆出厂类看起来像:

/* 
 */    
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类中获得DataSource Bean实例.

推荐答案

我设法解决了这个:

因此,在应用程序上下文中声明了我的数据源BEAN.另一方面,我的外部豆厂在根上下文中被声明.现在,根上下文中的bean无法在应用程序上下文中看到bean.因此,我的外部豆类工厂中的BeanFactory属性从未初始化.我花了一些时间来弄清楚,但是值得庆幸的是,它奏效了!

本文地址:https://www.itbaoku.cn/post/1574974.html

问题描述

TO use a datasource in my log4j appender, I have written a custom appender. The appender tries to get the datasource as a spring bean. However, the appender is not able to get the bean. The technology stack I am using is: mybatis, tomcat, and spring.

My log4j files looks like so:

#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

The code for the custom appender is as follows:

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();
     }
}

The External Bean factory class looks like so:

/* 
 */    
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);
    }
}

Now, when the tomcat server starts,my guess is that it tries to initialize log4j. Thus, it calls getConnection method in the custom appender. This inturn calls the ExernalFactory.getBean(), however, the beanfactory property in External BeanFactory has not been initialized yet.
The error stack trace is as follows:

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)

Please tell me what I am doing wrong and how I can get the datasource bean instance in my appender class.

推荐答案

I managed to solve this one:

So, my datasource bean was declared in an application context. My external bean factory on the other hand was declared in the root context. Now, beans in the root context cannot see the beans in the application Context. So, the beanfactory property in my External Bean Factory never got initialized. It took me some time to figure it out, but thankfully, it worked!