0%

打包命令

命令 备注
package 编译和打包
install 编译和打包,同时放到本地仓库中
clean 删除项目路径下的target文件
compile 生成一个target目录,在该目录中包含一个classes文件夹
build 这个插件让你自己去配置执行目标
generate-sources 根据pom配置去生成源代码格式的包
-DskipTests 不执行测试用例,但编译测试用例类至target/test-classes下
-Dmaven.test.skip=true 不执行测试用例,也不编译测试用例类。

其他命令

命令参数 备注
mvn -v –version 显示版本信息;
mvn -V –show-version 显示版本信息后继续执行Maven其他目标;
mvn -h –help 显示帮助信息;
mvn -e –errors 控制Maven的日志级别,产生执行错误相关消息;
mvn -X –debug 控制Maven的日志级别,产生执行调试信息;
mvn -q –quiet 控制Maven的日志级别,仅仅显示错误;
mvn -Pxxx 激活 id 为 xxx的profile (如有多个,用逗号隔开);
mvn -Dxxx=yyy 指定Java全局属性;
mvn -o –offline 运行offline模式,不联网更新依赖;
mvn -N –non-recursive 仅在当前项目模块执行命令,不构建子模块;
mvn -pl –module_name 在指定模块上执行命令;
mvn -ff –fail-fast 遇到构建失败就直接退出;
mvn -fn –fail-never 无论项目结果如何,构建从不失败;
mvn -fae –fail-at-end 仅影响构建结果,允许不受影响的构建继续;
mvn -C –strict-checksums 如果校验码不匹配的话,构建失败;
mvn -c –lax-checksums 如果校验码不匹配的话,产生告警;
mvn -U 强制更新snapshot类型的插件或依赖库(否则maven一天只会更新一次snapshot依赖);
mvn -npu –no-plugin-s 对任何相关的注册插件,不进行最新检查(使用该选项使Maven表现出稳定行为,该稳定行为基于本地仓库当前可用的所有插件版本);
mvn -cpu –check-plugin-updates 对任何相关的注册插件,强制进行最新检查(即使项目POM里明确规定了Maven插件版本,还是会强制更新);
mvn -up –update-plugins [mvn -cpu]的同义词;
mvn -B –batch-mode 在非交互(批处理)模式下运行(该模式下,当Mven需要输入时,它不会停下来接受用户的输入,而是使用合理的默认值);
mvn -f –file 强制使用备用的POM文件;
mvn -s –settings 用户配置文件的备用路径;
mvn -gs –global-settings 全局配置文件的备用路径;
mvn -emp –encrypt-master-password 加密主安全密码,存储到Maven settings文件里;
mvn -ep –encrypt-password 加密服务器密码,存储到Maven settings文件里;
mvn -npr –no-plugin-registry 对插件版本不使用~/.m2/plugin-registry.xml(插件注册表)里的配置;

本文地址: https://github.com/maxzhao-it/blog/post/48544/

CAP理论:

在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡

  • C A 满足的情况下,P不能满足的原因:

    数据同步(C)需要时间,也要正常的时间内响应(A),那么机器数量就要少,所以P就不满足

  • CP 满足的情况下,A不能满足的原因:

    数据同步(C)需要时间, 机器数量也多(P),但是同步数据需要时间,所以不能再正常时间内响应,所以A就不满足

  • AP 满足的情况下,C不能满足的原因:

    机器数量也多(P),正常的时间内响应(A),那么数据就不能及时同步到其他节点,所以C不满足

总有例外,比如阿里 Nacos

注册中心产品整体的差异总览

Nacos Eureka Consul CoreDNS Zookeeper
一致性协议 CP+AP AP CP CP
健康检查 TCP/HTTP/MYSQL/Client Beat Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
负载均衡策略 权重/ metadata/Selector Ribbon Fabio RoundRobin
雪崩保护
自动注销实例 支持 支持 不支持 不支持 支持
访问协议 HTTP/DNS HTTP HTTP/DNS DNS TCP
监听支持 支持 支持 支持 不支持 支持
多数据中心 支持 支持 支持 不支持 不支持
跨注册中心同步 支持 不支持 支持 不支持 不支持
SpringCloud集成 支持 支持 支持 不支持 不支持
Dubbo集成 支持 不支持 不支持 不支持 支持
K8S集成 支持 不支持 支持 支持 不支持

Java 开发越来越离不开阿里

分析参考链接:主流微服务注册中心浅析和对比

本文地址: https://github.com/maxzhao-it/blog/post/52272/

自定义Bootstrap配置

通过将项添加到名为org.springframework.cloud.bootstrap.BootstrapConfiguration的项下的/META-INF/spring.factories中.

当添加自定义BootstrapConfiguration,小心你添加类不是@ComponentScanned错误地进入你的“ 主 ”应用程序上下文,这里可能并不需要它们。为引导配置类使用单独的程序包名称,并确保@ComponentScan或带注释的配置类@SpringBootApplication尚未包含该名称。

spring.factories 有一套用法,从spring.factories中找到的类创建引导上下文,会在启动之前,将类型为ApplicationContextInitializer的所有@Beans添加到主SpringApplication

自定义引导程序Property源

中文文档

端点

对于Spring Boot Actuator应用程序,可以使用一些其他管理端点。您可以使用:

  • POST/actuator/env以更新Environment并重新绑定@ConfigurationProperties和日志级别。
  • /actuator/refresh重新加载引导上下文并刷新@RefreshScope beans。
  • /actuator/restart关闭ApplicationContext并重新启动(默认情况下禁用)。
  • /actuator/pause/actuator/resume用于调用Lifecycle方法(ApplicationContext中的stop()start())。
[注意]
如果禁用/actuator/restart端点,则/actuator/pause/actuator/resume端点也将被禁用,因为它们只是/actuator/restart的特例。

本文地址: https://github.com/maxzhao-it/blog/post/29799/

前言

官方案例的笔记

Nacos官方文档#启动服务发现

时间线——2021-04-19—
启动报错:hibernate-validator ,去掉 pom.xmlhibernate-validator,去掉 spring-boot-starter-web 中的 hibernate-validator

1
2
3
4
5
6
7
8
9
10
><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</exclusion>
</exclusions>
</dependency>

实现

依赖

provider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>

consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-openfeign.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
</dependencies>

版本说明 Wiki

打不开 github 的版本参考Nacos启动配置管理-SpringCloud(1)

配置

provider:port=8070

1
2
3
server.port=8070
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

consumer:port=8080

1
2
3
server.port=8080
spring.application.name=service-consumer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

代码

provider

通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {

public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}

@RestController
class EchoController {
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
public String echo(@PathVariable String string) {
return "Hello Nacos Discovery " + string;
}
}
}

consumer

通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能。给 RestTemplate 实例添加 @LoadBalanced 注解,开启 @LoadBalancedRibbon 的集成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(NacosConsumerApplication.class, args);
}

@RestController
public class TestController {

private final RestTemplate restTemplate;

@Autowired
public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;}

@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
public String echo(@PathVariable String str) {
return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
}
}
}

测试

启动 ProviderApplicationConsumerApplication ,调用 http://localhost:8080/echo/2018,返回内容为 Hello Nacos Discovery 2018

本文地址: https://github.com/maxzhao-it/blog/post/49625/

前言

Nacos官方文档#启动配置管理

时间线——2021-04-19—

Nacos 代码实例中的 nacos-spring-boot-example/pom.xml中的 SpringBoot:2.0.3.RELEASE ,其它 example 中的版本为 2.0.4.RELEASE 有可能会启动报错,改成 2.0.4.RELEASE

实现

依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${latest.version}</version>
</dependency>

组件版本关系

Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Version Dubbo Version Seata Version
2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE 1.8.0 1.4.1 4.4.0 2.7.8 1.3.0

毕业版本依赖关系(推荐使用)

Spring Cloud Version Spring Cloud Alibaba Version Spring Boot Version
Spring Cloud 2020.0 2021.1 2.4.2.RELEASE
Spring Cloud Hoxton.SR8 2.2.5.RELEASE 2.3.2.RELEASE

版本说明 Wiki

打不开 github 可以点这里

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# Nacos 控制台添加配置:
# 在 Nacos Spring Cloud 中,dataId 的完整格式如下:${prefix}-${spring.profiles.active}.${file-extension}
# spring.profiles.active 即为当前环境对应的 profile,当 spring.profiles.active 为空时,对应的连接符 - 也将不存在
# prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
# Data ID:example.properties
# Group:DEFAULT_GROUP
# 配置内容:useLocalCache=true
spring.application.name=example
spring.profiles.active=
# dataId 的 prefix
#spring.cloud.nacos.config.prefix:
# 指定配置的后缀,支持 properties、yaml、yml,默认为 properties
spring.cloud.nacos.config.file-extension=properties
#spring.cloud.nacos.config.file-extension=yaml

代码

通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {

@Value("${useLocalCache:false}")
private boolean useLocalCache;

@RequestMapping("/get")
public boolean get() {
return useLocalCache;
}
}

测试

  1. 首先通过调用 Nacos Open APINacos Server 发布配置:dataIdexample.properties,内容为useLocalCache=true

    1
    curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example.properties&group=DEFAULT_GROUP&content=useLocalCache=true"
  2. 运行 NacosConfigApplication,调用 curl http://localhost:8080/config/get,返回内容是 true

  3. 再次调用 Nacos Open APINacos server 发布配置:dataIdexample.properties,内容为useLocalCache=false

    1
    curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example.properties&group=DEFAULT_GROUP&content=useLocalCache=false"
  4. 再次访问 http://localhost:8080/config/get,此时返回内容为false,说明程序中的useLocalCache值已经被动态更新了。

附录

组件版本关系

Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Version Dubbo Version Seata Version
2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE 1.8.0 1.4.1 4.4.0 2.7.8 1.3.0
2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE 1.8.0 1.3.3 4.4.0 2.7.8 1.3.0
2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE 1.7.1 1.2.1 4.4.0 2.7.6 1.2.0
2.2.0.RELEASE 1.7.1 1.1.4 4.4.0 2.7.4.1 1.0.0
2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE 1.7.0 1.1.4 4.4.0 2.7.3 0.9.0
2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE 1.6.3 1.1.1 4.4.0 2.7.3 0.7.1

毕业版本依赖关系(推荐使用)

Spring Cloud Version Spring Cloud Alibaba Version Spring Boot Version
Spring Cloud 2020.0 2021.1 2.4.2.RELEASE
Spring Cloud Hoxton.SR8 2.2.5.RELEASE 2.3.2.RELEASE
Spring Cloud Greenwich.SR6 2.1.4.RELEASE 2.1.13.RELEASE
Spring Cloud Hoxton.SR3 2.2.1.RELEASE 2.2.5.RELEASE
Spring Cloud Hoxton.RELEASE 2.2.0.RELEASE 2.2.X.RELEASE
Spring Cloud Greenwich 2.1.2.RELEASE 2.1.X.RELEASE
Spring Cloud Finchley 2.0.4.RELEASE(停止维护,建议升级) 2.0.X.RELEASE
Spring Cloud Edgware 1.5.1.RELEASE(停止维护,建议升级) 1.5.X.RELEASE

本文地址: https://github.com/maxzhao-it/blog/post/15456/

高并发处理的日志优化

有以下几个方面:

  1. 使用 Log4j2 的异步日志
  2. 合理设置日志级别
  3. 合理分割日志文件
  4. 容器环境下的日志使用ES(不建议使用NFS等网络文件夹)

1、Log4j2 的异步日志

Log4j2 的同步、异步性能比较:
alt text
Log4j2 与其它日志比较:
alt text

查看地址

Log4j2的结构:
alt text
Log4j2日志输出流程:
alt text

配置方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<Configuration status="WARN">
<Appenders>
... <!-- your appenders here -->
</Appenders>
<Loggers>
<AsyncRoot level="info" includeLocation="false">
<AppenderRef ref="yourAppenderName"/>
</AsyncRoot>
<!-- 或者为特定logger配置 -->
<AsyncLogger name="com.example.MyClass" level="debug">
<AppenderRef ref="yourAppenderName"/>
</AsyncLogger>
</Loggers>
</Configuration>

注意:

  1. 异步日志可能会造成数据丢失,比如服务器宕机、容器宕机。
  2. 异步日志的顺序无法保证。可以配置异步线程池为 1

2、合理设置日志级别

避免日志滥用的最好方式是使用 DEBUG ,既有利于日志定位问题的速度,又能提高性能。

3、合理分割日志文件

一个示例:

1
2
3
4
5
6
7
8
9
10
11
<RollingFile name="ROLLING_FILE">
<PatternLayout pattern="${pattern}"/>
<Policies>
<!-- <OnStartupTriggeringPolicy />-->
<!--单个文件 超过2GB就分-->
<SizeBasedTriggeringPolicy size="2 GB"/>
<!-- <TimeBasedTriggeringPolicy />-->
</Policies>
<!--超过10个会自动删除-->
<DefaultRolloverStrategy max="10"/>
</RollingFile>

4、容器环境下的日志使用ES

Docker 环境

可直接使用宿主机

K8S 环境

使用临时路径并开启缓存,通过 Filebeat Sidecar 采集日志数据到 ES,通过Kibana查看日志。

本文地址: https://github.com/maxzhao-it/blog/post/2639945454/

前言

目前 JAVA 中使用最多的三大日志框架:

  • logbackSpringBoot 中的默认框架
  • log4j
  • log4j2

打印日志也面临着消耗性能,导致高并发性能下降。

优化日志一般也是从更换性能更高的日志框架做起。(对于以前的项目来讲,可以从其他日志框架切换到 log4j2,一般来讲,日志的性能会有一部分的提高。)

然后可以使用异步日志。关掉控制台日志输出等等。

log4j2 日志

配置 pom.xml

这里要注意, Springboot 原来会默认引入 logback

1
2
3
4
5
6
7
8
9
10
11
12

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--增加识别yaml格式依赖,加上这个才能辨认到log4j2.yml文件 ;spring-boot-starter 中也引入了 snakeyaml-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
</dependencies>

去掉 Springboot 原来的日志

其它地方引入的 spring-boot-starter-logging 也要去掉。

这里推荐一个 IDEA pluginMaven Helper.
打开 pom.xml 会在左下角有一个 Dependency analyzer 页面,可以搜索目标依赖
右键点击需要操作的依赖,可以很方便的 exclude

1
2
3
4
5
6
7
8
9
10
11

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>

配置 log4j2.yml

下面有简要列出了基础功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Configuration:
status: INFO
Properties: # 定义全局变量
Property:
- name: log.level.console
value: info
- name: log.path #日志存储路径
value: app_log
- name: project.name #日志项目名称
value: boot
Appenders:
Console:
name: CONSOLE
target: SYSTEM_OUT
PatternLayout:
pattern: "%d{yyyy-MM-dd HH:mm:ss,SSS}:%4p %t (%F:%L) - %m%n"
RollingFile:
# 输出到文件,超过64MB归档
- name: ROLLING_FILE
ignoreExceptions: false
fileName: ${log.path}/${project.name}.log
filePattern: "${log.path}/$${date:yyyy-MM}/${project.name} -%d{yyyy-MM-dd}-%i.log.gz"
PatternLayout:
pattern: "%d{yyyy-MM-dd HH:mm:ss,SSS}:%4p %t (%F:%L) - %m%n"
Policies:
# 日志大于 64MB 会生成新的日志
SizeBasedTriggeringPolicy:
size: "64 MB"
DefaultRolloverStrategy:
max: 1000
Loggers:
Root:
level: INFO
AppenderRef:
# 这里设置的 ref ,在 Logger 中不需要再次设置,Logger 继承了 Root
- ref: CONSOLE
- ref: ROLLING_FILE
Logger:
- name: boot
additivity: true
level: DEBUG
AppenderRef:
# logger 继承了 root 则这里不需要 `- ref: CONSOLE` 等 root 中已经存在的 `AppenderRef` 否则会造成重复打印

重复打印日志的原因

简单的问题

重复打印日志

Logger 继承了 Root,所以Root中的 AppenderRef 配置,都会被 Logger 继承过去。

如果不想 Logger 继承了 Root,只需要添加 additivity属性为 falseadditivity默认是为 true 的。

修改颜色

这里提供一个华丽胡哨的颜色,配置在 SYSTEM_OUT 中。

1
pattern: "%clr{%d{yyyy-MM-dd HH:mm:ss,SSS}}{faint}:%clr{%-5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%-32t]}{faint} %clr{%-40.40c{1.} (%F:%L)}{cyan} %clr{:}{faint} %m%n%xwEx"

过滤器

1
2
3
4
5
6
7
8
9
10
RollingFile: # 输出到文件,超过256MB归档
- name: ROLLING_FILE
ignoreExceptions: false
fileName: ${log.path}/${project.name}.log
thresholdFilter:
level: INFO
# 高于 info 拦截
onMatch: ACCEPT
# 低于 info 拦截
onMismatch: DENY

是按严重(重要)程度来分的(如下6种):
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

1
2
3
4
5
6
onMatch="ACCEPT" 表示匹配该级别及以上
onMatch="DENY" 表示不匹配该级别及以上
onMatch="NEUTRAL" 表示该级别及以上的,由下一个filter处理,如果当前是最后一个,则表示匹配该级别及以上
onMismatch="ACCEPT" 表示匹配该级别以下
onMismatch="NEUTRAL" 表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则不匹配该级别以下的
onMismatch="DENY" 表示不匹配该级别以下的

Appender类型

Appender 描述
ConsoleAppender 主要用于将日志打印到控制台
FailoverAppender 配置多个Appender,当primary Appender挂了的时候可以切换到Standby Appender
FileAppender 将日志写入文件
JDBCAppender 将日志写入到数据库
JMS Appender 将日志写入消息broker
HttpAppender 将日志写入http服务端
KafkaAppender 将日志写入kafka服务端
NoSQLAppender 将日志写入NoSQL服务端
MongoDB 将日志写入MongoDB
RollingFileAppender 将日志写入回滚文件
SocketAppender 将日志写入socket服务器

本文地址: https://github.com/maxzhao-it/blog/post/26399/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


var scope = angular.element($('.btn_send')).scope();
var notNames = [];
scope.$watch('chatContent', function (newValue, oldValue) {
if (newValue === oldValue) {
return;
}
var msg = newValue[newValue.length - 1];
if (msg.MsgType != 1 || !msg.MMActualContent) {
/*当前不为文字时*/
return;
}
if (msg.MMIsSend) {
/*我发送的消息不考虑*/
console.log('我发送的消息不考虑');
return;
}
if (msg.MMActualContent.length == 4) {
// $('#editArea').html('当前' + msg.MMActualContent + '可能是成语');
// scope.editAreaCtn = '当前' + msg.MMActualContent + '可能是成语';
var nameStart = msg.MMActualContent.substring(3);
$.ajax({
// url: 'http://127.0.0.1:8888/chengyu/name_start?nameStart=' + nameStart + '&notNames=' + notNames.join(','),
url: 'http://127.0.0.1:8888/chengyu/name?name=' + msg.MMActualContent + '&notNames=' + notNames.join(','),
success: (resp) => {
if (resp&&resp!='null') {
console.log('获取成语成功 =====> ' + resp);
scope.editAreaCtn = resp;
setTimeout(() => {
$('.btn_send').click();
}, 200)
}else{
console.log('获取成语失败 =====> ' + resp);
}
}
});
}
console.log("=====custom-====== ", msg.MMActualContent);
}, true);

//var msg=scope.chatContent[scope.chatContent.length-1];
//msg.MMActualContent

本文地址: https://github.com/maxzhao-it/blog/post/17024/

概述

遇到一个需求: 需要执行 bean 中不固定的方法.

当前第一想法是像 MQ 配置文件一样, 动态配置 beanmethod.

最终确定用反射来实现.

目的

  • 用反射调用 bean 的方法.

实现

反射实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

@Service
@Slf4j
public class ChatRouter {
public SocketResult goRoute(String currentUserId, String message) {
String beanName = "testBean";
String methodName = "testMethod";
Object bean = SpringBeanUtil.getApplicationContext().getBean(beanName);
try {
Class<?> c = bean.getClass();
//获取被调用的类的方法test2,参数类型为String
Method m = c.getMethod(methodName, String.class, String.class);
/*执行当前 bean 对象的方法*/
Object result = m.invoke(bean, currentUserId, message);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}

TestBean

1
2
3
4
5
6
7
8

@Service("testBean")
public class TestBean {
public String testMethod(String currentUserId, String message) {
/*这里调用其他 bean 不影响*/
return "调用成功";
}
}

SpringBeanUtil 动态获取 bean

当前工具类用于根据 bean name 获取 bean 对象使用.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

@Component
public class SpringBeanUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringBeanUtil.applicationContext = applicationContext;
}

public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}

本文地址: https://github.com/maxzhao-it/blog/post/2700/