请评论我的 Spring-Rabbitmq AMQP 记录器 class

Please comment on my Spring-Rabbit AQMP logger class

我正在编写一个 SpringBoot 4 应用程序,并希望使用 RabbitMQ 3.5.5 从我的控制器发送日志消息。最初我写了一个 class,使用 Java API,来封装 Rabbit 的东西,但我被告知每个客户端请求将在不同的线程中处理。我还被告知,如果我每次发送时都分配一个通道,性能会很差,所以我应该使用 Spring RabbitMQ 实现来为我处理这个问题。

我重写了我的 class,希望有人愿意看一下。虽然它看起来工作得很好,但我对 SpringBoot 还是个新手,所以我觉得我对这个魔法是如何实现的还没有完全理解。我对此 class 的主要担忧是 (1) 线程安全和 (2) 性能。

目前,我在我的控制器中自动装配这个 class 是这样的:

@Autowired
private RabbitLogger rl;

我认为这为我提供了一个新的 RabbitLogger 实例,如果是这样,我认为我在线程安全方面做得很好,但我不确定。新的 RabbitLogger class 使用 Spring RabbitMQ 客户端实现。

我会 post 我的 class 和下面控制器的摘录。在记录器 class 中,我使用 spring.rabbitmq application.properties 作为用户名、密码和主机,并为队列名称和交换名称创建了自己的属性。

非常感谢您的想法。这是我组织中一个非常引人注目的项目,我真的需要它尽可能接近完美。谢谢。

@Configuration
public class RabbitLogger 
{
    @Value("${rabbit.queue:uadec_queue}")
    private String queueName;

    @Value("${rabbit.exchange:uadec_exchange}")
    private String exchangeName;

    @Value("${spring.rabbitmq.username}")
    private String rabbitUn;

    @Value("${spring.rabbitmq.password}")
    private String rabbitPw;

    @Value("${spring.rabbitmq.host}")
    private String rabbitHost;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    private void dumpConfig()
    {
        Logger.getGlobal().config(() -> "RabbitMQ Hostname: " + rabbitHost);
        Logger.getGlobal().config(() -> "RabbitMQ Exchange Name: " + exchangeName);
        Logger.getGlobal().config(() -> "RabbitMQ Queue Name: " + queueName);
        Logger.getGlobal().config(() -> "RabbitMQ Username: " + rabbitUn);
        Logger.getGlobal().config(() -> "RabbitMQ Password: " + rabbitPw);
    }

    public void logLoginUserNameNotFound(String IP, String s)
    {
        String message = IP + "\tLOGIN_USER_NOT_FOUND\t" + s;
        send(message);
    }

    public void logLoginBadPassword(String IP, String s)
    {
        String message = IP + "\tLOGIN_BAD_PASSWORD\t" + s;

        send(message);
    }


    public void logLoginSuccess(String IP, String s)
    {
        String message = IP + "\tLOGIN_SUCCESS\t" + s;

        send(message);
    }

    public void logDecisionRendered(String IP, String userId, String decision)
    {
        String message = IP + "\tDECISION_RENDERED\t" + userId + "\t" + decision;

        send(message);
    }

    private void send(String s)
    {
        if(rabbitTemplate == null)
        {
            Logger.getGlobal().fine(() -> "Unable to send Rabbit Message - rabbitTemplate is null");
            return;
        }

        if(queueName == null)
        {
            Logger.getGlobal().fine(() -> "Unable to send Rabbit Message - queueName is null");
            return;
        }

        String time = ZonedDateTime.now().toString();
        String message = time + "\t" + s + "\r\n";

        try
        {
            rabbitTemplate.convertAndSend(queueName, message);

            Logger.getGlobal().finest(() -> "Sent Rabbit Message: " + message);
        }
        catch(Exception e)
        {
            Logger.getGlobal().finest(() -> "Failed sending Rabbit Message: " + message);
            Logger.getGlobal().finest(() -> "Exception: " + e);
        }
    }
}

控制器是这样启动的:

@Controller
public class Login_FormController 
{
    private String decisionText = null;

    @Autowired
    private AdminDataRepository adRep;

    @Autowired
    private ApplicantCredentialsDataRepository acRep;

    @Autowired
    private RabbitLogger rl;

    @RequestMapping(value="/", method=RequestMethod.POST)
    public String loginSumbit(@Valid 
        @ModelAttribute("loginForm") ApplicantCredentialsData applicantCredentialsData,
        BindingResult br,
        Model model,
        HttpServletRequest serReq)
    {

        Blah Blah Blah

        // Log something
        rl.logLoginSuccess(remoteIp, userId);

    }

不确定我们可以如何帮助您,我真的很高兴看到您的问题的其他观点,但从我的角度来看,一切看起来都很好。

是的,有很多特定于您的项目的代码,但是您正确使用了 Spring AMQP。

RabbitTemplate 确实是线程安全的,因此无需担心并发 convertAndSend 调用。

密码

@Autowired
private RabbitLogger rl;

在您的 Login_FormController 中(顺便说一句,从 Java 转换的角度来看,class 名称很糟糕)表示它将仅使用容器中的一个实例 - singleton。那只是因为你的 RabbitLogger 没有定义任何 scope。我想说的是,如果您没有正确理解 Spring,请不要担心这个问题。暂时阅读有关此事的文档!

Spring 引导 魔法 是围绕应用程序上下文(你的!)一些内置 bean,如 RabbitTemplate 基于来自 application.properties 的常用选项。您可以从 RabbitAutoConfiguration.

中找到它是如何完成的

你还有什么好说的?..

我们有一个用于 log4jlogbackAmqpAppender 作为开箱即用的组件,以允许遵循标准日志记录系统配置和 API , 但将日志发送到 AMQP。