Grpc 整合 Nacos SpringBoot 日常使用(Java版本)包括 Jwt 认证

本文项目地址

感兴趣的小伙伴可以支持一下点个 Star。
项目地址https://gitcode.net/qq_42875345/grpcdemo

前言

最近感到有点子迷茫,天天写业务代码有点麻木,趁着有点空闲时间去了解了下 Grpc 这个框架,一方面是听说他很火,支持多种语言。另一方面也是为了将来可能需要用到他,未雨绸缪一下,当然了本文只是基于使用上来带大家入门 Grpc,应付基本的日常开发足够了,后续有时间给大家分析一波源码,帮助大家更好的理解 net.devh.boot.grpc 这个包里面关于自动装配、Grpc服务是如何注册、@GrpcService以及内置注解是如何生效的。

Grpc 传输介质介绍

Grpc 是基于 Protobuf 序列化传输的,为啥用 Protobuf 那就是传输效率高,Grpc 的基础代码是根据我们编写的 Protobuf 文件,通过 Protobuf 插件逆向生成的,有点类似于 Mybatis 的逆向生成,所以在学习 Grpc 前,我们要先了解下 Protobuf 的基础语法。

Protobuf 语法介绍

就着本文使用到的 proto 文件来介绍吧,如下几个参数类似于 java 中的 import、papackage 这些关键字,对应的作用已用注释说明。

//是否生成多个文件
option java_multiple_files = false;
//生成的代码放在所指定的包下面
option java_package = "com.zzh.grpcapi.rpc";
//生成文件名称
option java_outer_classname = "UserServiceProto";

当我们通过 Protobuf 插件编译完成后,项目对应的 com.zzh.grpcapi.rpc 目录下就会出现如下图的这些文件。我们日后的开发用的就是这些逆向生成的代码。

在这里插入图片描述
但是生成文件到指定目录需要一个前提就是我们做过相关的配置,也就是引入我们的 Protobuf 插件。

Protobuf 插件指定生成文件目录(Maven插件)

在 bulid 下面的 plugins 标签中添加一个 如下的一个 plugin 节点即可,plugin 代码在文章末尾的附录里有。
在这里插入图片描述
插件代码一般都是拿来即用的,唯一需要大家做出一点改动的地方就是如下这俩个节点,outputDirectory 改成你项目中,对应的生成文件需要放的位置,clearOutputDirectory 节点用 false 就行,开发中类中的方法会出现增增减减的情况,用 false 表示对应的逆向文件只更新我们 proto 文件中更新的内容,其他内容不变。而用 true 表示,先删除目录下的所有文件,然后重新生成我们的代码。

<!--指定生成文件目录位置-->
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<!--false:追加,true:清除指定目录下的文件然后覆盖-->
<clearOutputDirectory>false</clearOutputDirectory>

plugin 配置都加好了后 ,依次点击 protobuf: compile , protobuf: compile-custom 即可。(我们的 proto 文件夹必须是在 main 文件下面,不然 proto 文件找不到

在这里插入图片描述

Grpc 服务端配置(YML文件)

除了需要配置一下 Grpc 服务的端口号,其他配置均为 Nacos 的大众配置,为什么 Grpc 需要额外的配置一下端口号呢?原因也很简单 Grpc 是基于 Netty 的二次开发,不管是 Grpc 还是 Netty 最终实现远程通信都离不开 Scoket 这个东西,而 server port 指定的是我们 tomcat 的端口号,grpc server port 指定的则是 Scoket 的端口号。这俩个端口号是俩码事(后续推出一遍源码博客帮助大家了解吧~)

server:
  port: 8089
grpc:
  server:
    port: 8090
spring:
  application:
    name: grpcservice
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848

配置好了后记得引入我们的 api 模块,加入到 dependencies 中即可。

<dependency>
    <groupId>com.zzh</groupId>
    <artifactId>grpcapi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

Grpc 服务端 Api 接口实现

我们实现 UserServiceGrpc 中的以 Base 结尾的那个类即可,这个类也是大家业务开发中需要实现的类,然后客户端调用的也是我们实现类中的方法逻辑。指的注意的是:Grpc 的返回数据、异常返回和我们 Java 中接口的返回有点不太一样。

  1. Grpc 返回数据:通过 onNext 方法返回客户端数据。且 onCompleted 方法必须调用,代表此次 Grpc 服务通信结束。
  2. Grpc 异常返回: 通过 ReponseObserver.onError() 方法返回。

这些代码都是固定的,为了加深理解,读者自行去测试看效果将会事半功倍。本文只阐述最基本的代码通用模版。常用的开发中也就是这些个东西了。最后我们用 @GrpcService 注解标注此类为 Grpc 服务类即可。

在这里插入图片描述

Grpc 通信客户端配置(YML文件)

里面就是一些 Nacos 注册的配置还有 Grpc 探测服务的配置,值得一提的是,如项目整合了 Nacos,那么 address: static://127.0.0.1:8090 下文配置中的这一行代码将无需配置,原因很简单,客户端和服务端注册在同一个 Nacos 里面,当客户端需要用到服务端时,根据服务名称寻找即可找到对应的 Grpc 服务,但是当项目没整合 Nacos 时,则需要我们手动配置 Grpc 服务地址。

server:
  port: 8088
grpc:
  client:
    grpc-service-test:
      #address: static://127.0.0.1:8090 #整合nacos后无需设置,grrpc服务端地址,根据服务名寻找对应的服务
      negotiation-type: plaintext
      enableKeepAlive: true
      keepAliveWithoutCalls: true
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
  application:
    name: grpcclient

注意我们的 grpc-service-test 不是乱配的,需要和 Nacos 中的服务名对应。
在这里插入图片描述

Grpc 客户端服务调用(阻塞式)

客户端都配置好了之后,我们利用 @GrpcClient 注解,注入我们的 Grpc 服务端实现类,即可在客户端完成调用。日常开发用下图中的阻塞客户端即可,意思就是这次 Grpc 远程调用必须等待服务端处理好请求,客户端收到请求后接着处理客户端后续的逻辑(日常开发最常用的也是这种模式),为阻塞模式。那有的读者就会问了,有没有非阻塞的调用呀,有的请看下文。
在这里插入图片描述

Grpc 客户端服务调用(服务端单向流)

大致代码和阻塞式差不多,但是区别在于 Grpc 的调用是靠 UserServiceStub 完成的,也就是非阻塞客户端(使用场景:聊天室、股票代码、实时天气),非阻塞模式的调用,在不阻塞客户端逻辑的情况下,先出给接口响应,后续的 Grpc 推送过来的消息采用监听的模式接收,整个过程是异步的。因此 Grpc 贴心的为我们提供了 onNext、onError、onCompleted 这三大方法分别代表如下意思。

  1. onNext:Grpc 服务端每推送一条消息给客户端,onNext 方法里面都会同步监听到这条数据
  2. onError:Grpc 服务端发生异常时,onError 方法里面会同步监听到错误信息
  3. onCompleted: Grpc 服务端调用 onCompleted 方法时,客户端同步触发 onCompleted 方法。

在这里插入图片描述
当然非阻塞式方法需要对应的 proto 文件支持,需要哪边(客户端、服务端)具备主动推送消息的能力就在对应的参数(请求参数、返回参数)前面添加 stream 。

rpc loginStream (LoginVo) returns (stream LoginDto) {}

Grpc 服务端非阻塞模式(服务端单向流)

客户端改造好了后,服务端用 for 循环每隔 2 秒,依次调用 onNext 方法即可,客户端的 onNext 监听方法里面也会每隔 2 秒收到来自 Grpc 服务端的消息。

在这里插入图片描述

演示效果:每隔 2 秒收到来自服务端推送过来的消息

在这里插入图片描述

Grpc 双向流

Grpc 还有一个功能就是可以实现,客户端与服务端互推消息。 有点类似于 WebScoket 。使用起来也很简单,客户端直接调用双向流的方法,里面还是那三个监听方法,监听 Grpc 服务端推送过来的消息,同时客户端利用调用方法返回的 StreamObserver 可以去主动推送给 Grpc 服务端。完成了客户端的主动推送。

在这里插入图片描述

而服务端也是利用 StreamObserver 完成去监听客户端发来的消息和推送给客户端消息。下图的代码我是客户端发过来一条,服务端就处理一条推送回给客户端的,各位可以根据自己的业务逻辑来。

在这里插入图片描述

到此 Grpc 几种常用的模式就介绍完了,接下来在说一下 Grpc 中的拦截器吧,这个大家也有可能会用到。

客户端 Grpc 拦截器日志记录、jwt 请求头统一添加

有的时候为了保证 Grpc 服务的安全,一般都需要做认证才能进行调用,利用客户端拦截器我们可以对 Grpc 调用进行日志记录,也可以对所有的 Grpc 调用添加统一的请求头,做 Jwt 校验啥的。我们只需实现 ClientInterceptor 接口,然后在所在类上面加上 @GrpcGlobalClientInterceptor 注解即可。标注这个是全局客户端拦截器。下面的代码我会在所有 Grpc 请求调用前为当期请求设置一个 jwt 请求头,这个 jwt 是服务端给我们颁发的,如果客户端没有检测到 jwt 的存在会携带 ak、sk 参数主动去请求服务端的 jwt 获取接口,完成后存储于客户端,可能有人会说了,jwt 不是无状态的吗?你这样不就成了有状态的了。答:jwt 存储在客户端,相当于我们的前端页面,对于服务端依旧是无状态的。

/**
 * 全局设置 jwt 请求头
 */
@Slf4j
@GrpcGlobalClientInterceptor
public class ClientInterceptor implements io.grpc.ClientInterceptor {
    @Value("${grpc.auth.ak}")
    private String ak;
    @Value("${grpc.auth.sk}")
    private String sk;
    @Value("${grpc.auth.host}")
    private String host;
    @Value("${grpc.auth.port}")
    private int port;
    @Value("${grpc.auth.name}")
    private String serviceName;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
        CallOptions myCallOptions = callOptions
                //.withDeadlineAfter(2, TimeUnit.SECONDS) //设置超时
                .withCallCredentials(new CallCredentials() {
                    @Override
                    public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
                        Metadata metadata = new Metadata();
                        Object token = redisTemplate.opsForValue().get(serviceName);
                        String jwt = "";
                        if (null == token) {
                            //根据服务名进行寻找服务,利用 ak、sk 自动登录,将 token 存储于 redis
                            ManagedChannel managedChannel = ManagedChannelBuilder.forTarget(serviceName).usePlaintext().build();
                            UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub = UserServiceGrpc.newBlockingStub(managedChannel);
                            UserServiceProto.LoginDto login = userServiceBlockingStub
                                    .login(UserServiceProto.LoginVo.newBuilder()
                                            .setName(ak)
                                            .setPassword(sk)
                                            .build());
                            jwt = login.getToken();
                            redisTemplate.opsForValue().set(serviceName, jwt);
                        } else {
                            jwt = String.valueOf(token);
                        }
                        //设置 jwt 请求头
                        metadata.put(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER), "Bearer " + jwt);
                        applier.apply(metadata);
                    }
                    @Override
                    public void thisUsesUnstableApi() {
                    }
                });
        return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, myCallOptions)) {
            @Override
            public void sendMessage(ReqT message) {
                //日志记录
                log.info("ClientInterceptor#interceptCall#SimpleForwardingClientCall#sendMessage## request method: {} , param: {} ", method.getFullMethodName(), message.toString());
                super.sendMessage(message);
            }
        };
    }
}

但是上面的代码有一个问题,如果当前项目需要调用多个不同的 Grpc 服务,且每个 Grpc 服务都有各自的认证方式的话,那么这种全局添加请求头这种方式就不太适合了,那么这个时候我们根据调用的 Grpc 服务名(通过 requestInfo.getAuthority()获取),去请求对应的认证接口,然后把拿到的 token 放到请求头或者是哪,这个属于业务问题了,读者根据自己的需求来即可。
在这里插入图片描述

服务端 Grpc 拦截器权限校验

大致逻辑就是如果没带 jwt 请求头提示客户端没权限访问,带了 jwt 请求头去校验 jwt 是否合法,合法了放行。放行和阻塞的代码都是固定的,大家根据自己需要设置对应的 Status、还有上下文参数即可。

@GrpcGlobalServerInterceptor
public class AuthInterceptor implements ServerInterceptor {
    private JwtParser parser = Jwts.parser().setSigningKey(AuthConstant.JWT_KEY);
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        String authorization = metadata.get(Metadata.Key.of(AuthConstant.AUTH_HEADER, Metadata.ASCII_STRING_MARSHALLER));
        Status status = Status.OK;
        //简单模拟了一下白名单,实际开发中放配置文件
        if ("UserService/login".equals(serverCall.getMethodDescriptor().getFullMethodName()))
            //放行
            return Contexts.interceptCall(Context.current(), serverCall, metadata, serverCallHandler);
        if (authorization == null) {
            status = Status.UNAUTHENTICATED.withDescription("miss authentication token");
        } else if (!authorization.startsWith(AuthConstant.AUTH_TOKEN_TYPE)) {
            status = Status.UNAUTHENTICATED.withDescription("unknown token type");
        } else {
            Jws<Claims> claims = null;
            String token = authorization.substring(AuthConstant.AUTH_TOKEN_TYPE.length()).trim();
            try {
                claims = parser.parseClaimsJws(token);
            } catch (JwtException e) {
                status = Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e);
            }
            if (claims != null) {
                //设置全局上下文属性,下游通过 AuthConstant.AUTH_CLIENT_ID.get(Context.current()) 获取设置的值
                Context ctx = Context.current().withValue(AuthConstant.AUTH_CLIENT_ID, claims.getBody().getSubject());
                //放行
                return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler);
            }
        }
        //阻塞
        serverCall.close(status, new Metadata());
        return new ServerCall.Listener<ReqT>() {
        };
    }
}

public interface AuthConstant {
    SecretKey JWT_KEY = Keys.hmacShaKeyFor("zzhhaoshuaizzhhaoshuaizzhhaoshuaizzhhaoshuai".getBytes());
    Context.Key<String> AUTH_CLIENT_ID = Context.key("userId");
    String AUTH_HEADER = "Authorization";
    String AUTH_TOKEN_TYPE = "Bearer";
}

到此你已经可以利用 Grpc 进行日常业务开发了,剩下的就是搬砖操作了~~~~~~~~~~~~

附录(本文所用到的Grpc插件、proto文件、maven依赖)

本文使用到的 Grpc 插件

   <extensions>
        <!-- 兼容eclipse和netbeans中protobuf代码生成插件-->
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.6.2</version>
        </extension>
    </extensions>
    <plugins>
        <!-- grpc代码生成插件 -->
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.6.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                <outputDirectory>${basedir}/src/main/java</outputDirectory>
                <clearOutputDirectory>false</clearOutputDirectory>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

本文用到的 Nacos、Grpc、Jwt Maven 依赖

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <grpc.version>1.44.0</grpc.version>
        <protobuf.version>3.19.2</protobuf.version>
        <protoc.version>3.19.2</protoc.version>
        <gson.version>2.8.9</gson.version>
        <spring-boot.version>2.3.9.RELEASE</spring-boot.version>

    </properties>

    <!-- gRPC公共依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- gRPC bom -->
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-bom</artifactId>
                <version>${grpc.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- protobuf依赖 -->
            <dependency>
                <groupId>com.google.protobuf</groupId>
                <artifactId>protobuf-java-util</artifactId>
                <version>${protobuf.version}</version>
            </dependency>
            <!-- prevent downgrade via protobuf-java-util -->
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>${gson.version}</version>
            </dependency>
        </dependencies>



    </dependencyManagement>


    <dependencies>

        <!-- nacos注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-config</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
<!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <!-- gRPC依赖 -->
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
        </dependency>

        <!-- protobuf依赖 -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
        </dependency>
        <!-- prevent downgrade via protobuf-java-util -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-spring-boot-starter</artifactId>
            <version>2.14.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.zzh</groupId>
            <artifactId>grpcapi</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

本文测试用到的 proto 文件

syntax = "proto3";
//是否生成多个文件
option java_multiple_files = false;
//生成的代码放在所指定的包下面
option java_package = "com.zzh.grpcapi.rpc";
//生成文件名称
option java_outer_classname = "UserServiceProto";
service UserService {
  rpc login (LoginVo) returns (LoginDto) {}
  rpc loginStream (LoginVo) returns (stream LoginDto) {}
  rpc loginDoubleStream (stream LoginVo) returns (stream LoginDto) {}
}

message LoginVo {
  string name = 1;
  string password = 2;

}

message LoginDto {
  string name = 1;
  repeated string ids = 3;
  string password = 2;
  string token=4;
}

小咸鱼的技术窝

关注不迷路,日后分享更多技术干货,B站、优快云、微信公众号同名,名称都是(小咸鱼的技术窝)更多详情在主页
在这里插入图片描述

<think>嗯,用户问的是Java微服务技术有哪些,以及资深Java开发工程师应该具备哪些技术。首先,我需要确定用户的需求。他们可能正在准备面试,或者想要提升自己的技能,或者需要评估团队的技术栈。用户提到“资深工程师”,所以需要深入技术细节,而不仅仅是表面的工具列表。 首先,Java微服务的技术栈有哪些呢?常见的框架有Spring BootSpring Cloud、Micronaut、Quarkus。需要详细说明每个框架的特点和使用场景。比如Spring Boot是基础,Spring Cloud提供了服务发现、配置管理等功能。Micronaut和Quarkus适合云原生,启动快,内存占用低。 接下来是通信机制。RESTful API是最常见的,但资深工程师可能还需要了解gRPC的高性能,或者消息队列如Kafka、RabbitMQ。这里要区分同步和异步通信的区别,以及它们的适用场景。 服务注册与发现,常用的有Eureka、Consul、Zookeeper。需要解释它们的作用,比如Eureka是Netflix开源的,而Consul多数据中心支持更好。配置中心的话,Spring Cloud Config和Consul、Nacos都是选项,Nacos在国内比较流行,可以提一下。 容错和负载均衡方面,Hystrix虽然已经停更,但Resilience4J是替代品。负载均衡器如Ribbon和Spring Cloud LoadBalancer,需要说明它们的整合方式。网关有Zuul和Spring Cloud Gateway,后者性能更好,支持异步。 分布式事务和链路追踪,这些都是微服务中的难点。Seata处理分布式事务,Sleuth和Zipkin用于追踪,还有SkyWalking和Pinpoint也是可选的工具。需要强调监控的重要性,比如Prometheus和Grafana的组合,以及ELK栈处理日志。 容器化和云原生方面,Docker和Kubernetes是基础,但也要提到Service Mesh如Istio,虽然可能更偏向架构师层面的知识,但资深工程师应该了解。 然后是资深工程师需要具备的技术能力。首先框架原理,比如Spring Boot的自动配置、启动流程,Spring Cloud的组件整合。源码理解能力很重要,能够排查问题。 分布式系统设计,CAP定理、服务拆分原则(DDD)、一致性协议如Raft、Paxos。需要结合实际案例,比如如何解决数据一致性或脑裂问题。 性能优化方面,JVM调优、垃圾回收算法、线程池优化。高并发场景下的缓存策略,缓存穿透、雪崩的解决方案,Redis集群的使用。 云原生和DevOps,CI/CD流程,Kubernetes的运维,Service Mesh的应用。监控和日志分析能力,能够快速定位问题。 安全方面,OAuth2、JWT、常见漏洞防护。数据库优化,分库分表、读写分离,ORM框架的深度使用,比如MyBatis和Hibernate。 软技能方面,系统设计能力,问题排查经验,技术选型的考量因素,如团队熟悉度、社区活跃度、维护成本。领导力和沟通能力也是资深工程师必备的。 最后要总结,强调技术深度和广度,解决问题的能力,以及持续学习的重要性。可能用户想了解如何从中级进阶到资深,所以需要涵盖全面的知识点,并给出学习方向。</think>我将从Java微服务技术栈和资深工程师技术要求两个维度,为您系统梳理关键知识点: 一、Java微服务核心技术体系 ($$架构图见下方文字描述$$) ``` [服务治理] - [通信机制] - [数据管理] | | | v v v 注册中心 REST/gRPC 分布式事务 配置中心 消息队列 数据库中间件 熔断降级 缓存体系 ``` 1. 核心框架与工具 - 基础框架:Spring Boot(必须精通自动配置原理) - 服务治理:Spring Cloud Alibaba/Nacos(注册中心+配置中心) - 服务通信:OpenFeign(声明式HTTP)、gRPC(高性能RPC) - 消息中间件:Kafka(高吞吐)、RabbitMQ(事务消息) - 容错机制:Sentinel(流量控制)、Resilience4j(熔断降级) 2. 分布式关键组件 $$分布式事务方案 = TCC模式 \cup Saga模式 \cup 消息最终一致性$$ - 事务协调:Seata(AT/TCC模式) - 数据缓存:Redis Cluster(分布式锁、缓存穿透解决方案) - 配置管理:Apollo(灰度发布能力) - 链路追踪:SkyWalking(全链路监控) 3. 云原生技术栈 - 容器化:Docker(镜像优化技巧)、Kubernetes(Service/Pod原理) - 服务网格:Istio(流量治理) - 服务编排:Helm Chart(应用打包) 二、资深Java工程师技术能力矩阵 1. 深度技术能力 - JVM原理:内存模型($$JMM = Happens-Before原则 \cup 内存屏障$$)、GC算法调优 - 并发编程:线程池($$ThreadPoolExecutor_{corePoolSize,workQueue}$$)、AQS原理 - 框架源码:Spring循环依赖解决、MyBatis执行器体系 - 性能优化:Arthas诊断、JMH基准测试 2. 架构设计能力 - DDD实践:限界上下文划分($$BoundedContext = UbiquitousLanguage \cap ContextMap$$) - 容灾设计:多活架构、故障演练(Chaos Engineering) - 安全体系:OAuth2.0授权码模式、防重放攻击 3. 工程化能力 - CI/CD:Jenkins Pipeline优化、镜像构建规范 - 质量保障:精准测试(流量录制回放) - 可观测性:Metrics埋点($$QPS = \frac{TotalRequests}{TimeWindow}$$)、日志结构化 三、技术决策维度 当进行技术选型时,需综合评估: $$技术选型评估函数 = 0.4\times社区活跃度 + 0.3\times团队熟悉度 + 0.2\times扩展性 + 0.1\times运维成本$$ 典型面试考察点: 1. 如何设计秒杀系统的降级策略? 2. 分布式ID生成方案选型(Snowflake vs Leaf)? 3. 线上Full GC频繁的排查路径? 4. 如何实现蓝绿发布无损上线? 建议学习路径: 1. 精读《深入理解Java虚拟机》 2. 研究Spring Cloud Alibaba源码 3. 实践Kubernetes Operator开发 4. 参与开源中间件贡献(如Sentinel) 资深工程师的核心价值在于:能根据业务特征选择合适技术方案,建立完善的监控预警体系,并具备复杂问题定位的系统方法论。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小咸鱼的技术窝

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值