項目中有個需求,需要log4j2.xml加載application.yml的屬性,折騰了半天,貼代碼吧:
1.自定義啟動監聽ApplicationStartedEventListener,代碼中標紅的就是從yml中讀取的屬性,然后通過MDC設置到log4j2的上下文
package com.wm.dcm.utils; import org.slf4j.MDC; import org.springframework.boot.SpringApplication; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.GenericApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.ResolvableType; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; /** * @ClassName: MyApplicationStartedEventListener * @Description:TODO * @author: SUN * @date: 2017年9月19日 下午5:51:04 * */ public class ApplicationStartedEventListener implements GenericApplicationListener { public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; private static Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class, ApplicationFailedEvent.class }; private static Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class }; @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { ConfigurableEnvironment envi = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment(); MutablePropertySources mps = envi.getPropertySources(); PropertySource<?> ps = mps.get("applicationConfigurationProperties"); if (ps != null && ps.containsProperty("spring.kafka.bootstrap-servers")) { String kafkaUrl = (String) ps.getProperty("spring.kafka.bootstrap-servers"); //System.out.println(kafkaUrl); MDC.put("host", kafkaUrl); } if (ps != null && ps.containsProperty("logging.file")) { String fileName = (String) ps.getProperty("logging.file"); //System.out.println(kafkaUrl); MDC.put("fileName", fileName); } } } /* * (non-Javadoc) * * @see org.springframework.core.Ordered#getOrder() */ @Override public int getOrder() { // TODO Auto-generated method stub return DEFAULT_ORDER; } /* * (non-Javadoc) * * @see org.springframework.context.event.GenericApplicationListener# * supportsEventType(org.springframework.core.ResolvableType) */ @Override public boolean supportsEventType(ResolvableType resolvableType) { return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES); } @Override public boolean supportsSourceType(Class<?> sourceType) { return isAssignableFrom(sourceType, SOURCE_TYPES); } private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) { if (type != null) { for (Class<?> supportedType : supportedTypes) { if (supportedType.isAssignableFrom(type)) { return true; } } } return false; } }
2.在Application啟動類中添加自定義的啟動監聽ApplicationStartedEventListener
package com.wm.dcm.db; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.logging.LoggingApplicationListener; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.ComponentScan; import org.springframework.core.env.Environment; import org.springframework.kafka.annotation.EnableKafka; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import com.wm.dcm.constant.LogTypeAndLevel; import com.wm.dcm.utils.ApplicationStartedEventListener; @SpringBootApplication @EnableScheduling @ComponentScan(basePackages = { "com.wm.dcm" }) @EnableKafka @EnableAsync public class DBApplication { private String bootstrap; public String getBootstrap() { return bootstrap; } public void setBootstrap(String bootstrap) { this.bootstrap = bootstrap; } /** * The main method. * * @param args * the arguments * @throws Exception */ public static void main(String[] args) throws Exception { // System.out.println(env); SpringApplication app = new SpringApplication(DBApplication.class); Set<ApplicationListener<?>> ls = app.getListeners(); ApplicationStartedEventListener asel = new ApplicationStartedEventListener(); app.addListeners(asel); app.run(args); } }
3.在log4j2.xml中使用MDC定義的屬性,標紅的就是使用方式
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="info"> <Appenders> <RollingFile name="RollingFile" fileName="logs/${ctx:fileName}" filePattern="logs/$${date:yyyy-MM}/${ctx:fileName}-%d{MM-dd-yyyy}-%i.log.gz" immediateFlush="true" append="true"> <PatternLayout charset="UTF-8" pattern="[%-5p] %d[%t] [%c] - %m%n" /> <SizeBasedTriggeringPolicy size="50MB" /> <!-- DefaultRolloverStrategy屬性如不設置,則默認為最多同一文件夾下7個文件,這里設置了20 --> <DefaultRolloverStrategy max="20" /> </RollingFile> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout charset="UTF-8" pattern="[%-5p] %d[%t] [%c] - %m%n" /> </Console> <Kafka name="Kafka" topic="wmdcm_log"> <JSONLayout complete="false" compact="true" locationInfo="true" /> <Property name="bootstrap.servers" value="${ctx:host}"/> </Kafka> </Appenders> <Loggers> <!-- root loggers <AppenderRef ref="Console" /> --> <Root level="info" includeLocation="true"> <AppenderRef ref="RollingFile" /> <AppenderRef ref="Console" /> <AppenderRef ref="Kafka" /> </Root> <Logger name="org.apache.kafka" level="ERROR" /> <Logger name="org.springframework.kafka" level="ERROR" /> </Loggers> </Configuration>