spring中Bean的生命周期浅谈--rpc嵌入spring

文章目录

具体的有关spring中的Bean的声明周期的博客可以参考:
一文读懂 Spring Bean 的生命周期
@PostConstruct、afterPropertiesSet和init-method的执行顺序

第一篇博文中指出Bean的加载顺序如下:

在我写的简短代码中:分别实现了 EnvironmentAware,BeanPostProcessor,InitializingBean并分别重写了其中的:setEnvironment()、postProcessBeforeInitialization()、afterPropertiesSet()方法,按照上文参考博客中指出的Bean的加载顺序,上面列举的顺序就应该是正确的,但实现中却发现点不一样的。

整体代码如下:

java 复制代码
package part1.Server.integration.configuration;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import part1.Server.integration.RpcService;
import part1.Server.provider.ServiceProvider;
import part1.Server.server.RpcServer;
import part1.Server.server.impl.NettyRPCRPCServer;

/**
 * @Author: wt
 * @Description: 提供者后置处理器
 * @DateTime: 2024/11/07 23:14
 **/
@Slf4j
@Configuration
public class ProviderPostProcessor implements InitializingBean,BeanPostProcessor, EnvironmentAware{



    // 通过@Value注解读取配置文件更改为通过EnvironmentAware方法读取
//    @Value("${rpc.server.host:127.0.0.1}")
    private String host;

//    @Value("${rpc.server.port:9999}")
    private int port;
    private ServiceProvider serviceProvider;

    private RpcServer rpcServer;

    /**
     * 服务注册,在Spring容器初始化Bean之前执行,通过Spring的BeanPostProcessor机制自动触发
     * 实现的是「BeanPostProcessor」中的接口
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        ensureServiceProviderInitialized();
        Class<?> beanClass = bean.getClass();
        // 找到bean上带有 RpcService 注解的类
        RpcService rpcService = beanClass.getAnnotation(RpcService.class);
        if (rpcService == null){
            return bean;
        }
        String group = rpcService.group();
        String version = rpcService.version();
        log.info("获取提供方服务现实bean的实现类类{},组号{},版本号{}",beanClass,group,version);
        serviceProvider.provideServiceInterface(bean, rpcService);
        return bean;
    }

    /**
     * 在Spring容器加载配置文件并「初始化完成后」执行 ------> 启动 RPC 服务
     * 实现的是「Initialization」中的接口
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        ensureServiceProviderInitialized();
        Thread t = new Thread(() -> {
            try {
                log.info("服务端启动线程,主机号:{}, 端口:{}", host, port);
                rpcServer.start(port);
            } catch (Exception e) {
                log.error("启动RPC失败", e);
            }
        });
        // 守护线程,随主线程退出而停止
        t.setDaemon(true);
        t.start();

    }

    public void ensureServiceProviderInitialized(){
        // 双重检验确保只被初始化一次
        if(serviceProvider == null){
            serviceProvider = new ServiceProvider(host,port);
            rpcServer = new NettyRPCRPCServer(serviceProvider);
        }
    }

    /**
     * 读取配置文件,实现EnvironmentAware接口,提供访问Spring环境变量的能力
     * 实现的是「EnvironmentAware」中的接口
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        this.host = environment.getProperty("rpc.server.host", "127.0.0.1");
        this.port = Integer.parseInt(environment.getProperty("rpc.server.port", "9999"));
        log.info("RPC服务端host:{},端口port:{}", host, port);
    }
}

将服务端初始化接口设置在postProcessBeforeInitialization中,那么此时按照上面指出的执行顺序,在afterPropertiesSet()中rpcServer已经初始化完成了,然而我的执行结果却不符合预期。

执行结果:

RPC启动失败,此时rpcServer是null的。

随后将服务端初始化接口设置在afterPropertiesSet(),此时如下:

此时能够顺利初始化。

暂时这个问题没有得到有效的解决,虽然不影响我目前的效果。后续继续探究。

相关推荐
上进小菜猪18 分钟前
测试自动化Replay:让数据库迁移测试回归真实场景的一把“利器”
后端
Python私教21 分钟前
FastAPI × SQLAlchemy 2.0 Async:从“能跑”到“可压测”的完整工程实践
后端
小裕哥略帅25 分钟前
订单管理--实时算出在途数量、收货数量、到货数量、已发货数量和未发货数量
java·开发语言
Python私教26 分钟前
FastAPI × Loguru:从“能跑”到“可运维”的日志实战
后端
Dxxyyyy43 分钟前
零基础学JAVA--Day27(注释+异常+异常处理方法)
java·开发语言
Craaaayon1 小时前
如何选择两种缓存更新策略(写缓存+异步写库;写数据库+异步更新缓存)
java·数据库·redis·后端·缓存·mybatis
AAA卷不动了1 小时前
JVM(二)------ 类加载、初始化与单例模式的联系
java·jvm·单例模式
一 乐1 小时前
点餐|智能点餐系统|基于java+ Springboot的动端的点餐系统小程序(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·小程序·论文
少许极端2 小时前
算法奇妙屋(十)-队列+宽搜(BFS)
java·数据结构·算法·bfs·宽度优先·队列
唐僧洗头爱飘柔95272 小时前
【GORM(3)】Go的跨时代ORM框架!—— 数据库连接、配置参数;本文从0开始教会如何配置GORM的数据库
开发语言·数据库·后端·golang·gorm·orm框架·dsn