一:JMS
JMS是一种与厂商无关的 API,用来访问收发系统消息,它类似于JDBC(Java Database Connectivity)。这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。常见的MQ种类有ActiveMQ、RocketMQ、RabbitMQ、Kafka等。
如图所示是 JMS的PTP工作模式。里面有几个比较重要的概念,如Producer、Consumer、Destination等,下面是其解释:
- Producer:创建并发送消息的JMS客户
- Consumer:接收消息的JMS客户
- Destination:目的地,也称消息队列(ActiveMQQueue),是实际的消息源
- Topic:一种支持发送消息给多个订阅者的机制
- Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收
二:业务模拟
我们模拟现在无论是什么类型系统大都具备的一种模块–评价模块。常见的如电商购物评论模块、在线购票评价模块等。我们以一个较简单的评价模块来阐述例子。
该例子以标准三层架构方式进行编码,ORM采用的是注解JPA。ActiveMQ的配置步骤请参考这篇文章:ActiveMQ的安装
三:使用ActiveMQ进行消息转发与处理
1:Entity层创建
@Table
@Entity
public class Comment {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Integer commentId;
@Column(length = 8)
private String userName;
@Column
private String userComment;
@Column
private Date commentDate;
// 省略无参、满参构造器及setter、getter方法
}
2:Repository层创建
请注意这里的参数相比Entity层少了一个主键id,原因是因为数据表的id设计为自增类型,为了测试方便就不用手动插入id了。
这里的 insertCommentBean()
方法就是我们模拟用户评论的抽象方法。
public interface CommentRepository extends JpaRepository<Comment, Integer> {
@Modifying
@Transactional
@Query(value = "insert into csdn_test.comment (user_name, user_comment, comment_date) values(?1, ?2, ?3)", nativeQuery = true)
int insertCommentBean(String userName, String userComment, Date commentDate);
}
3:Service及Impl层创建
在Service层我们需要模拟一个标准的插入方法(间接调用)及异步插入方法(直接调用)。Service层如下:
(注意要先写同步插入方法,待Producer、Consumer创建好后再写异步插入的方法)
public interface CommentService {
void asyncSaveComment(CommentBean commentBean);
void syncSaveComment(CommentBean commentBean);
}
Impl层如下:
(注意Producer的注入是在Producer层完成后才实现的;异步队列的信息发送是在Service层的对应抽象方法写后才实现的)
@Service
public class CommentServiceImpl implements CommentService {
@Resource
CommentProducer commentProducer;
@Resource
CommentRepository commentRepository;
// 创建队列
Destination destination = new ActiveMQQueue("comment.queue");
@Override
public void asyncSaveComment(CommentBean commentBean) {
// 队列信息的发送
commentProducer.sendMessage((ActiveMQQueue) destination, commentBean);
}
@Override
public void syncSaveComment(CommentBean commentBean) {
commentRepository.insertCommentBean(commentBean.getUserName(), commentBean.getUserComment(), new Date());
}
}
4:Producer创建
这里注入JmsTemple进行消息队列的发送
@Service
public class CommentProducer {
@Resource
JmsTemplate jmsTemplate;
public void sendMessage(ActiveMQQueue destination, final CommentBean commentBean){
jmsTemplate.convertAndSend(destination, commentBean);
}
}
5:Consumer创建
这里要注意的就是队列的监听。
@Component
public class CommentConsumer {
@Resource
CommentService commentService;
// 注解进行监听相应的队列,注意队列destination不要写错
@JmsListener(destination = "comment.queue")
public void receiveQueue(CommentBean commentBean){
commentService.syncSaveComment(commentBean);
}
}
6:Controller创建
我们在Controller层就直接模拟数据就行了,内容如下:
@RestController
public class CommentController {
@Resource
CommentService commentService;
@RequestMapping(value = "/comment", method = RequestMethod.GET)
public void commentController() {
System.out.println("------> EXECUTE.");
CommentBean commentBean = new CommentBean("jack", "Great experience for me.", new Date());
commentService.asyncSaveComment(commentBean);
}
}
四:测试
访问comment,数据表即被插入如下行记录。