从Apollo初始化Log4j2的配置

本文详细介绍了如何从Apollo配置中心初始化Log4j2。在与Spring整合时遇到的问题是由于ConfigUtil初始化顺序导致,解决方案是在Spring启动之前加载Log4j2。文章提到了两种解决办法,包括Hook Apollo的NamespaceHandler以及通过添加commons-logging的bridge依赖来确保Log4j2在Spring启动前被加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从Apollo初始化Log4j2的配置

1. 实现步骤

通过编写ApolloLog4j2ConfigurationFactory类继承ConfigurationFactory,然后重写getConfiguration方法,在获取log4j2初始配置信息时从Apollo中读取配置信息并初始化log4j2

实现代码:

package com.dm.dmga.log4j;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder;

import java.net.URI;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;

/**
 * Log4j2的Apollo配置类
 * <dl>
 * <dt>主要实现功能:</dt>
 * <dd>
 * <ol>
 * <li>log4j2初始化时通过该类从Apollo加载相应的log4j2的配置信息</li>
 * <li>当通过Apollo修改log4j2配置后,能立即生效。例如,动态修改日志级别。</li>
 * </ol>
 * </dd>
 * </dl>
 *
 * @author zxb
 * @version 1.0.0
 * 2018年05月16日 10:10
 * @since 1.0.0
 */
@Plugin(name = "ApolloLog4j2ConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(50)
public class ApolloLog4j2ConfigurationFactory extends ConfigurationFactory {
   

    /** Log4j2的NameSpace名称 */
    private static final String LOG4J2_NAMESPACE = "dmga-dmdg.log4j2";

    @Override
    protected String[] getSupportedTypes() {
        return new String[]{
  "*"};
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
        return getConfiguration(loggerContext, source.toString(), null);
    }

    @Override
    public Configuration getConfiguration(LoggerContext loggerContext, String name, URI configLocation) {
        // 从Apollo读取log4j2配置
        Config config = ConfigService.getConfig(LOG4J2_NAMESPACE);
        Set<String> propertyNames = config.getPropertyNames();

        Properties properties = new Properties();
        for (String propertyName : propertyNames) {
            String propertyValue = config.getProperty(propertyName, null);
            properties.setProperty(propertyName, propertyValue);
        }

        // 添加log4j2配置的监听器
        config.addChangeListener(new Log4j2ConfigChangeListener(properties));

        // 构造log4j2的Configuration
        return new PropertiesConfigurationBuilder()
                .setRootProperties(copyProperties(properties))
                .setLoggerContext(loggerContext)
                .build();
    }

    /**
     * 复制Properties
     *
     * @param properties 原Properties对象
     * @return 新Properties对象
     */
    private Properties copyProperties(Properties properties) {
        Properties newProperties = new Properties();

        Enumeration<String> enumeration = (Enumeration<String>) properties.propertyNames();
        while (enumeration.hasMoreElements()) {
            String propertyName = enumeration.nextElement();
            newProperties.put(propertyName, properties.getProperty(propertyName));
        }
        return newProperties;
    }

    private class Log4j2ConfigChangeListener implements ConfigChangeListener {
   

        private Properties configProperties;

        public Log4j2ConfigChangeListener(Properties configProperties) {
            this.configProperties = configProperties;
        }

        public void onChange(ConfigChangeEvent changeEvent) {
            String newValue;
            ConfigChange configChange;

            for (String changedKey : changeEvent.changedKeys()) {
                configChange = changeEvent.getChange(changedKey);
                newValue = configChange.getNewValue();
                configProperties.put(changedKey, newValue);
            }

            // 构造新配置并应用到LoggerContext
            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
            Configuration newConfiguration = new PropertiesConfigurationBuilder()
                    .setRootProperties(copyProperties(configProperties))
                    .setLoggerContext(ctx)
                    .build();
            ctx.updateLoggers(newConfiguration);
        }
    }
}

2. 问题描述

该代码在与Spring整合时出现问题,部分报错信息如下:

com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Tried proxying com.ctrip.framework.apollo.util.ConfigUtil to support a circular dependency, but it is not an interface.
  at com.ctrip.framework.apollo.internals.DefaultInjector$ApolloModule.configure(DefaultInjector.java:59)
  while locating com.ctrip.framework.apollo.util.ConfigUtil

1 error
    at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028)
    at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054)
    at com.ctrip.framework.apollo.internals.DefaultInjector.getInstance(DefaultInjector.java:38)
    at com.ctrip.framework.apollo.build.ApolloInjector.getInstance(ApolloInjector.java:35)
    at com.ctrip.framework.apollo.spi.DefaultConfigFactory.<init>(DefaultConfigFactory.java:29)
    at com.ctrip.framework.apollo.spi.DefaultConfigFactory$$FastClassByGuice$$5ee2e445.newInstance(<generated>)
    at com.google.inject.internal.DefaultConstructionProxyFactory$FastClassProxy.newInstance(DefaultConstructionProxyFactory.java:
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值