참고한 사이트 : https://codenotfound.com/spring-jms-activemq-example.html
공부할만곳 : https://blog.outsider.ne.kr/985
JMS
사전에 도커가 설치되어야한다.
https://hub.docker.com/r/rmohr/activemq 사이트를 참고해서 ACTIVEMQ를 실행시키자.
docker pull rmohr/activemq
docker run -p 61616:61616 -p 8161:8161 rmohr/activemq
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
JNDI
스프링 부트 애플리케이션을 JEE 컨테니어네 배포할 때, 컨테이너에 미리 설정된 ConnectionFactory를 사용할 수 있다.
이를 가능하게 하려면 spring-jms 라이브러리와 javax.jms-api 의존성이 필요하다.
javax.jms-api는 JEE 컨테이너에서 제공되기 떄문에 provided로 표시한다.
또는 하나의 스타터를 정의하고 액티브MQ나 아르테미스의 의존성을 제외시킬수도있다. 그러나 필요한 의존성만을 등록하는 방식이 더 쉽다.
JNDI를 사용할수있을때, 스프링 부트는 먼저 ConnectionFactory의 JNDI레지스터가 잘 알려진 네임스페이스인 java/JmsXA와 java:/XAConnectionFactory를 먼저 탐지하거나, spring.jms.jndi-name 속성으로 설정한 네임스페이스를 탐지한다. 그리고 자동으로 JndiDestinationResolver를 만들어 JNDI에서 큐와 토픽을 탐지할 수 있다. 이는 기본적으로 목표 지점을 동적으로 생성 가능하게 한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<scope>provided</scope>
</dependency>
#spring.activemq.broker-url= 연결할 브로커 URL,
# 기본값 인메모리 브로커일경우 vm://localhost?broker.persistent-false, 아닌경우 tcp://localhost:61616
#spring.activemq.user= 브로커에 연결할 때 사용하는 사용자 이름, 기본값 없음
#spring.activemq.password= 브로커에 연결할 때 사용하는 사용자 비번, 기본값 없음
#spring.activemq.in-memory= 내장된 브로커를 사용한다. 기본값 true.
# 명시적으로 spring.activemq.broker-url를 설정했을경우 무시
#spring.activemq.non-blocking-redelivery= 롤백 메시지를 재전송하기 전에 메시지 전송을 중지한다.
# 중지되지 않을 경우 메시지 전송 순서가 보장되지 않는다. 기본값 false
#spring.activemq.close-timeout= 닫힘 효과가 나타날 때까지 기다리는 시간, 기본값 15초
#spring.activemq.send-timeout= 브로커로부터 응답이 올 때까지 기다리는 시간, 기본값 0(무제한)
#spring.activemq.packages.trust-all= JMS사용메시지 전송시 자바의 객체 직렬화 기능을 사용할 경우
# 모든 패키지의 클래스를 신뢰할 수 있어야 한다. 기본값은 none이다.
#spring.activemq.packages.trusted= 세미콜론(;)으로 분리된 신뢰할 수 있는 패키지 리스트
spring.activemq.broker-url=tcp://localhost:61616
spring.jms.template.receive-timeout=500ms
또는
@Bean
public ConnectionFactory connectionFactory(){
var con = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
con.setClientID("~~");
con.setCloseTimeout(500);
return con;
}
package com.example.demo.activemqApp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
public class Receiver {
private static final Logger LOGGER =
LoggerFactory.getLogger(Receiver.class);
@JmsListener(destination = "helloworld.q")
public void receive(String message) {
LOGGER.info("received message='{}'", message);
}
@JmsListener(destination = "time-queue")
public void timereceive(String message) {
LOGGER.info("received message='{}'", message);
}
}
package com.example.demo.activemqApp;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
@Configuration
@EnableJms
public class ReceiverConfig {
@Value("${spring.activemq.broker-url}")
private String brokerUrl;
@Bean
public ActiveMQConnectionFactory receiverActiveMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(brokerUrl);
return activeMQConnectionFactory;
}
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory
.setConnectionFactory(receiverActiveMQConnectionFactory());
return factory;
}
@Bean
public Receiver receiver() {
return new Receiver();
}
}
package com.example.demo.activemqApp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
public class Sender {
private static final Logger LOGGER =
LoggerFactory.getLogger(Sender.class);
@Autowired
private JmsTemplate jmsTemplate;
public void send(String message) {
LOGGER.info("sending message='{}'", message);
jmsTemplate.convertAndSend("helloworld.q", message);
}
public void timesend() {
LOGGER.info("sending message='{}'", "Current Date & Time is :"+LocalDateTime.now());
jmsTemplate.convertAndSend("time-queue","Current Date & Time is :"+ LocalDateTime.now());
}
}
package com.example.demo.activemqApp;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
@Configuration
public class SenderConfig {
@Value("${spring.activemq.broker-url}")
private String brokerUrl;
@Bean
public ActiveMQConnectionFactory senderActiveMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(brokerUrl);
return activeMQConnectionFactory;
}
@Bean
public CachingConnectionFactory cachingConnectionFactory() {
return new CachingConnectionFactory(
senderActiveMQConnectionFactory());
}
@Bean
public JmsTemplate jmsTemplate() {
return new JmsTemplate(cachingConnectionFactory());
}
@Bean
public Sender sender() {
return new Sender();
}
}
package com.example.demo.activemqApp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Slf4j
@Component
public class JmsActiveMQApplication implements ApplicationRunner {
@Resource
private Sender sender;
@Override
public void run(ApplicationArguments args) throws Exception {
sender.send("Hello Spring JMS ActiveMQ!");
}
@Scheduled(fixedRate = 2000) // 2sec
public void sendTime(){
sender.timesend();
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.4.RELEASE) 2020-02-15 05:20:14.915 INFO 17888 --- [ restartedMain] com.example.demo.DemoApplication : Starting DemoApplication on DESKTOP-6HPEM1U with PID 17888 (D:\example\springboot2_DB_example1\target\classes started by k in D:\example\springboot2_DB_example1) 2020-02-15 05:20:14.918 INFO 17888 --- [ restartedMain] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-02-15 05:20:14.983 INFO 17888 --- [ restartedMain] o.s.b.devtools.restart.ChangeableUrls : The Class-Path manifest attribute in C:\Users\k\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.2\jaxb-runtime-2.3.2.jar referenced one or more files that do not exist: file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.xml.bind-api-2.3.2.jar,file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/txw2-2.3.2.jar,file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/istack-commons-runtime-3.0.8.jar,file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/stax-ex-1.8.1.jar,file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/FastInfoset-1.2.16.jar,file:/C:/Users/k/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.activation-api-1.2.1.jar 2020-02-15 05:20:14.983 INFO 17888 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2020-02-15 05:20:14.983 INFO 17888 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG' 2020-02-15 05:20:15.582 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! 2020-02-15 05:20:15.582 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode. 2020-02-15 05:20:15.605 INFO 17888 --- [ restartedMain] .RepositoryConfigurationExtensionSupport : Spring Data JDBC - Could not safely identify store assignment for repository candidate interface com.example.demo.JdbcTemplate.CustomerRepository. If you want this repository to be a JDBC repository, consider annotating your entities with one of these annotations: org.springframework.data.relational.core.mapping.Table. 2020-02-15 05:20:15.606 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 21ms. Found 0 JDBC repository interfaces. 2020-02-15 05:20:15.612 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! 2020-02-15 05:20:15.612 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2020-02-15 05:20:15.628 INFO 17888 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 13ms. Found 1 JPA repository interfaces. 2020-02-15 05:20:15.842 INFO 17888 --- [ restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2020-02-15 05:20:16.050 INFO 17888 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-02-15 05:20:16.057 INFO 17888 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-02-15 05:20:16.057 INFO 17888 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30] 2020-02-15 05:20:16.125 INFO 17888 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-02-15 05:20:16.125 INFO 17888 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1141 ms 2020-02-15 05:20:16.179 INFO 17888 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2020-02-15 05:20:16.436 INFO 17888 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2020-02-15 05:20:17.550 INFO 17888 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2020-02-15 05:20:17.725 INFO 17888 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2020-02-15 05:20:17.787 INFO 17888 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate Core {5.4.10.Final} 2020-02-15 05:20:17.858 INFO 17888 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final} 2020-02-15 05:20:17.934 INFO 17888 --- [ restartedMain] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect 2020-02-15 05:20:18.300 INFO 17888 --- [ restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2020-02-15 05:20:18.306 INFO 17888 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2020-02-15 05:20:18.388 WARN 17888 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2020-02-15 05:20:18.653 INFO 17888 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-02-15 05:20:18.884 INFO 17888 --- [ restartedMain] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler' 2020-02-15 05:20:19.117 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:19.117991900' 2020-02-15 05:20:19.137 INFO 17888 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-02-15 05:20:19.138 INFO 17888 --- [ restartedMain] com.example.demo.DemoApplication : Started DemoApplication in 4.643 seconds (JVM running for 5.543) 2020-02-15 05:20:19.139 INFO 17888 --- [ restartedMain] com.example.demo.activemqApp.Sender : sending message='Hello Spring JMS ActiveMQ!' 2020-02-15 05:20:19.152 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:19.118991400' 2020-02-15 05:20:19.208 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Hello Spring JMS ActiveMQ!' 2020-02-15 05:20:21.114 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:21.114739100' 2020-02-15 05:20:21.117 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:21.114739100' 2020-02-15 05:20:23.115 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:23.115304900' 2020-02-15 05:20:23.118 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:23.115304900' 2020-02-15 05:20:25.116 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:25.116556300' 2020-02-15 05:20:25.118 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:25.116556300' 2020-02-15 05:20:27.116 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:27.116349500' 2020-02-15 05:20:27.118 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:27.116349500' 2020-02-15 05:20:29.115 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:29.115735600' 2020-02-15 05:20:29.117 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:29.115735600' 2020-02-15 05:20:31.115 INFO 17888 --- [ scheduling-1] com.example.demo.activemqApp.Sender : sending message='Current Date & Time is :2020-02-15T05:20:31.115878700' 2020-02-15 05:20:31.120 INFO 17888 --- [enerContainer-1] com.example.demo.activemqApp.Receiver : received message='Current Date & Time is :2020-02-15T05:20:31.115878700' Process finished with exit code -1 | cs |
# JmsTemplate 속성
#spring.jms.template.default-destination= 별도 목적지를 명시하지 않았을 때 메시지를 전송하고 수신받는 기본 목적지
#spring.jms.template.delivery-delay= 메시지 전송 시 지연 시간을 설정한다.
#spring.jms.template.delivery-mode= 전송 방식을 영구 메시지 방식으로 할지 미영구 메시지 방식으로 할지를 설정한다.
# 명시적으로 qos-enabled가 true로 설정돼야 한다.
#spring.jms.template.priority= 메시지 전송 우선순위를 설정한다. 기본값 none(우선순위없음), 명시적으로 qos-enabled가 true로 설정돼야 한다.
#spring.jms.template.qos-enabled= QOS 설정을 활성화 한다. 메시지의 전송 우선순위와 전송방식, 데이터 유효 기간을 추가로 설정한다. 기본값 false
#spring.jms.template.receive-timeout= 메시지 수신 타임아웃을 설정한다. 기본값 무한
#spring.jms.template.time-to-live= JMS 메시지의 유효 기간을 설정한다. qos-enabled 속성이 true여야 한다.
#spring.jms.pub-sub-domain= 기본 도착지가 토픽 또는 큐다. 기본값 false는 큐를 의미
# 위의 설정에 따라 JmsTemplate은 DestinationResolver와 MessageConverter의 구현 빈 인스턴스를 찾아 자동으로 설정
# 빈 인스턴스를 못 찾을 경우 기본 빈인 DynamicDestinationResolver와 SimpleMessageConverter를 사용
# JMS 메시지 컨버터인 SimpleMessageConverter 클래스
# 유형 -> JMS 메시지 유형
# java.lang.String -> javax.jms.TextMessage
# java.util.Map -> javax.jms.MapMessage
# java.io.Serializable -> javax.jms.ObjectMessage
# byte[] -> javax.jms.ByteMessage
'WEB > 스프링 부트 2' 카테고리의 다른 글
RabbitMQ (0) | 2020.02.17 |
---|---|
@JmsListener (0) | 2020.02.17 |
JavaMail (0) | 2020.02.14 |
JDBC, Mapper / JPA / TestEntityManagerTest / SessionFactory (0) | 2020.02.14 |
MySQL 연결 / 스프링 schema.sql, data.sql / Flyway (0) | 2020.02.13 |