请评论我的 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
.
中找到它是如何完成的
你还有什么好说的?..
我们有一个用于 log4j
和 logback
的 AmqpAppender
作为开箱即用的组件,以允许遵循标准日志记录系统配置和 API , 但将日志发送到 AMQP。
我正在编写一个 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
.
你还有什么好说的?..
我们有一个用于 log4j
和 logback
的 AmqpAppender
作为开箱即用的组件,以允许遵循标准日志记录系统配置和 API , 但将日志发送到 AMQP。