当前位置: 首页 > news >正文

天津公司网站建设费江苏推广网站建设业务

天津公司网站建设费,江苏推广网站建设业务,郑州住房和城乡建设部网站,英文网站seo推广介绍 在我们使用log4j2或者logback打印日志时&#xff0c;输出的内容中通常是一定要加上服务名的。以log4j2为例&#xff1a; <!--输出控制台的配置--> <Console name"Console" target"SYSTEM_OUT"><!-- 输出日志的格式 --><Patter…

介绍

在我们使用log4j2或者logback打印日志时,输出的内容中通常是一定要加上服务名的。以log4j2为例:

<!--输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT"><!-- 输出日志的格式 --><PatternLayout pattern="server-case %d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n"/>
</Console>

服务名为server-case,输出的内容为

server-case 2023-09-15 17:44:38  INFO ServerCaseApplication:648 - No active profile set, falling back to default profiles: default
server-case 2023-09-15 17:44:39  INFO TomcatWebServer:108 - Tomcat initialized with port(s): 7081 (http)
server-case 2023-09-15 17:44:39  INFO Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-7081"]
server-case 2023-09-15 17:44:39  INFO StandardService:173 - Starting service [Tomcat]
...

但是有种情况,有的项目要部署在甲方内网或者连接甲方的资源。项目是同一套代码,但要服务于不同的甲方,所以一个项目会有不同的服务名的情况。

这样的话,服务名就不能写死,要根据不同的服务名来输出。

问题

有的人可能会想到直接设置一个对象实现EnvironmentAware接口中的setEnvironment(Environment environment),来获取environment来获取spring.application.name

但这样有问题,设置的这个对象是要在spring上下文中进行加载后才能获得environment,所以在这个对象加载之前的日志输出还是拿不到environment

@Component
public class Test implements EnvironmentAware {private Environment environment;@Overridepublic void setEnvironment(final Environment environment) {this.environment = environment;System.setProperty("applicationName", Objects.requireNonNull(environment.getProperty("spring.application.name")));}
}
<!--输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT"><!-- 输出日志的格式 --><PatternLayout pattern="${sys:applicationName} %d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n"/>
</Console>
${sys:applicationName} 2023-09-18 10:18:34  INFO ServerCaseApplication:55 - Starting ServerCaseApplication on lukuan with PID 21472 (D:\idea_work_my\gitee\cook-frame\server\server-case\target\classes started by lukuan in D:\idea_work_my\gitee\cook-frame)
${sys:applicationName} 2023-09-18 10:18:34  INFO ServerCaseApplication:648 - No active profile set, falling back to default profiles: default
${sys:applicationName} 2023-09-18 10:18:34  INFO TomcatWebServer:108 - Tomcat initialized with port(s): 7081 (http)
${sys:applicationName} 2023-09-18 10:18:34  INFO Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-7081"]
${sys:applicationName} 2023-09-18 10:18:34  INFO StandardService:173 - Starting service [Tomcat]
${sys:applicationName} 2023-09-18 10:18:34  INFO StandardEngine:173 - Starting Servlet engine: [Apache Tomcat/9.0.46]
${sys:applicationName} 2023-09-18 10:18:34  INFO [/]:173 - Initializing Spring embedded WebApplicationContext
${sys:applicationName} 2023-09-18 10:18:34  INFO ServletWebServerApplicationContext:285 - Root WebApplicationContext: initialization completed in 795 ms_ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ /               |         3.5.1 
service-case 2023-09-18 10:18:35  INFO ThreadPoolTaskExecutor:181 - Initializing ExecutorService 'applicationTaskExecutor'
service-case 2023-09-18 10:18:35  INFO PropertySourcedRequestMappingHandlerMapping:69 - Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
service-case 2023-09-18 10:18:35  INFO Http11NioProtocol:173 - Starting ProtocolHandler ["http-nio-7081"]
service-case 2023-09-18 10:18:35  INFO TomcatWebServer:220 - Tomcat started on port(s): 7081 (http) with context path ''

可以看到比较靠前的日志输出中的applicationName变量是没有被替换成真正的服务名的。

那怎么办呢?

分析

所以我们要从SpringBoot的启动过程入手

SpringApplication#run(String… args)
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}

突破点在environment的创建这步骤,所以分析prepareEnvironment(listeners, applicationArguments)看能不能实现我们想要的需求

SpringApplication#prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);//经过debug发现当这步方法执行完后,environment.getProperty("spring.application.name")是可以获取值listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}

listeners.environmentPrepared(environment);为关键点,environment.getProperty("spring.application.name")就是在此进行完成的,所以我们要进入分析。

SpringApplicationRunListeners#environmentPrepared
void environmentPrepared(ConfigurableEnvironment environment) {for (SpringApplicationRunListener listener : this.listeners) {listener.environmentPrepared(environment);}
}

listeners有一个实现类EventPublishingRunListener

public void environmentPrepared(ConfigurableEnvironment environment) {this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

这里是发布了一个ApplicationEnvironmentPreparedEvent事件。

既然有发布,就有监听。我们接下来分析下监听事件的逻辑

ConfigFileApplicationListener#onApplicationEvent
public void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationEnvironmentPreparedEvent) {onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);}if (event instanceof ApplicationPreparedEvent) {onApplicationPreparedEvent(event);}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);for (EnvironmentPostProcessor postProcessor : postProcessors) {postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());}
}

postProcessors有多个,其中ConfigFileApplicationListener就是设置spring.applicaton.name的值。至于怎么设置的,就不进去分析了,有兴趣的同学可以自行去仔细研究。

通常上述分析,我们知道了Environment设置spring.applicaton.name值的步骤,那么我们可不可以紧接着,这个设置步骤之后就进行自定义设值,然后让log4j2来取呢?

答案是当然可以!

让我们回到SpringApplicationRunListeners#environmentPrepared

SpringApplicationRunListeners#environmentPrepared
void environmentPrepared(ConfigurableEnvironment environment) {for (SpringApplicationRunListener listener : this.listeners) {listener.environmentPrepared(environment);}
}

默认listeners为一个,那我们只要自己实现一个,让listeners为2个,第一个默认执行完后,不就能紧接着执行我们的了吗,那我们分析下listeners是怎么来的

SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;
}

SpringFactoriesLoader.loadFactoryNames(type, classLoader)和自动装配的方法很像啊,那去看一眼

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

果然在文件中指定了org.springframework.boot.context.event.EventPublishingRunListener,也就是默认的SpringApplicationRunListener实现类。

然后在分析createSpringFactoriesInstances看看是如何加载的

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList<>(names.size());for (String name : names) {try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);T instance = (T) BeanUtils.instantiateClass(constructor, args);instances.add(instance);}catch (Throwable ex) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);}}return instances;
}

这里就是创建对象的过程了,用的是有参构造方法需要两个参数constructor, args,所以我们参考EventPublishingRunListener的结构来实现即可

实现

自定义SpringApplicationRunListener的实现类CustomEventPublishingRunListener

CustomEventPublishingRunListener
public class CustomEventPublishingRunListener implements SpringApplicationRunListener, Ordered {private static final String SPRING_APPLICATION_NAME = "spring.application.name";private final SpringApplication application;private final String[] args;public CustomEventPublishingRunListener(SpringApplication application, String[] args){this.application = application;this.args = args;}@Overridepublic int getOrder() {return 1;}@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {String applicationName = environment.getProperty(SPRING_APPLICATION_NAME);if (StringUtil.isNotEmpty(applicationName)) {System.setProperty("applicationName", applicationName);}}
}
  • 有参构造方法中的SpringApplication application, String[] args参数为固定的
  • getOrder返回的值要为1,因为EventPublishingRunListener中的getOrder返回值为0

在自动装配文件spring.factories指定位置

org.springframework.boot.SpringApplicationRunListener=\com.example.runlistener.CustomEventPublishingRunListener

在log4j2的xml文件中进行取值

<!--输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT"><!-- 输出日志的格式 --><PatternLayout pattern="${sys:applicationName} %d{yyyy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n"/>
</Console>

输出结果

service-case 2023-09-18 14:57:25  INFO ServerCaseApplication:55 - Starting ServerCaseApplication on lukuan with PID 20004 (D:\idea_work_my\gitee\cook-frame\server\server-case\target\classes started by lukuan in D:\idea_work_my\gitee\cook-frame)
service-case 2023-09-18 14:57:25  INFO ServerCaseApplication:648 - No active profile set, falling back to default profiles: default
service-case 2023-09-18 14:57:25  INFO TomcatWebServer:108 - Tomcat initialized with port(s): 7081 (http)
service-case 2023-09-18 14:57:25  INFO Http11NioProtocol:173 - Initializing ProtocolHandler ["http-nio-7081"]
service-case 2023-09-18 14:57:25  INFO StandardService:173 - Starting service [Tomcat]
service-case 2023-09-18 14:57:25  INFO StandardEngine:173 - Starting Servlet engine: [Apache Tomcat/9.0.46]
service-case 2023-09-18 14:57:25  INFO [/]:173 - Initializing Spring embedded WebApplicationContext
service-case 2023-09-18 14:57:25  INFO ServletWebServerApplicationContext:285 - Root WebApplicationContext: initialization completed in 716 ms_ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ /               |         3.5.1 
service-case 2023-09-18 14:57:26  INFO ThreadPoolTaskExecutor:181 - Initializing ExecutorService 'applicationTaskExecutor'
service-case 2023-09-18 14:57:26  INFO PropertySourcedRequestMappingHandlerMapping:69 - Mapped URL path [/v2/api-docs] onto method [springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation(String, HttpServletRequest)]
service-case 2023-09-18 14:57:26  INFO Http11NioProtocol:173 - Starting ProtocolHandler ["http-nio-7081"]
service-case 2023-09-18 14:57:26  INFO TomcatWebServer:220 - Tomcat started on port(s): 7081 (http) with context path ''
....

可以看到实现了我们想要的功能

http://www.yayakq.cn/news/878699/

相关文章:

  • 网站换空间 site办公室设计图片
  • 织梦网站程序模板wordpress 列表页模板
  • 网站建设和维护管理预算做网站怎么电话约客户
  • 大一html5网页设计代码泉州做网站优化价格
  • 太原微信网站南昌专业网站优化推广
  • 青岛网站建设招标济南网站制作价格
  • 北京网站优化推广效果金融企业网站模板
  • 网站开发教程百度云wordpress去-
  • 深圳 购物网站拉一条宽带要多少钱
  • 红色博客网站源码物流网站怎么做代理
  • 标签系统做的好的网站福州网站建设营销q479185700刷屏
  • 优秀网站psd建e网室内设计网背景墙
  • 可以在线做护理题的网站网站的外链是什么
  • 天猫网站建设的目的网络信息
  • html手机网站开发教程加盟型网站制作
  • 建设集约化网站的进展情况网站建设3a模型是什么意思
  • 如何建设好一个公司网站wordpress字体插件下载
  • 网站运营合同深圳外包网站公司
  • 网站设计的要求wordpress用户角色权限管理
  • 移动门户网站建设特点网站为什么做301
  • 湖南专业做网站公司安装wordpress出现乱码
  • 企业网站优化包括哪三个方面怎么进入网站管理系统
  • seo整站优化什么价格wordpress带颜色的文字
  • 长春做网站搜吉网传媒wordpress汉化插件下载地址
  • 重庆可视化网站制作我的个人网站怎么做
  • 国内网站开发的主流技术久久建筑网高空坠落专项应急预案
  • 中文网站做google广告好吗郑州做网站优化电话
  • 网站建站建设首选上海黔文信息科技有限公司2凡客诚品是什么牌子
  • 下列不能反应企业网站建立网络网站推广广告申请
  • 乌镇网站建设标书北京比较好的品牌设计公司