如何将Spring Boot JMS从ActiveMQ迁移到Oracle高级队列?

9

我正在学习Spring Boot和JMS的示例,但我还是新手。

由于我们使用Oracle,我想将Spring Boot& JMS示例从ActiveMQ迁移到Oracle高级队列。然而,我真的很难找到相关信息。

据我所知,我需要针对Oracle版本替换下面的代码,但我还没有找到如何替换。

@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                                                DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    // This provides all boot's default to this factory, including the message converter
    configurer.configure(factory, connectionFactory);
    // You could still override some of Boot's default if necessary.
    return factory;

源代码可在Github找到。

非常感谢您的帮助!


在我看来,这是有意为之的。如果你的代码运行在WebLogic上(它也是Oracle产品),那么设置就非常容易(参见http://danielveselka.blogspot.cz/2009/07/mdb-3-0-on-weblogic-103-using-oracle-aq.html)。恐怕其他应用服务器不提供JMS到AQ连接器(资源适配器)。 - ibre5041
不,我不想连接到WebLogic,而是直接连接到Oracle Advanced Queueing(AQ)。 在没有Spring Boot的情况下,我的程序使用:qconFactory = AQjmsFactory.getQueueConnectionFactory(hostName, serviceName, port, "thin"); qcon = qconFactory.createQueueConnection(userName, password); qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queueTable = ((AQjmsSession) qsession).getQueueTable(userName, queueTableName); queue = ((AQjmsSession) qsession).getQueue(userName, queueName); - dhmc
我想要解释的是,Oracle AQ可以作为标准的Java EE JMS提供者。这可能会使您从ActiveMQ的转换更加容易(实际上源代码中不需要进行任何更改)。但这只在某些情况下适用。 - ibre5041
我也对此很感兴趣。不是迁移,而是Spring中的Oracle AQ。 - codesmith
2个回答

4
以下配置将解决您的问题。 1-创建配置。对于此答案,我已经将所有配置文件紧凑地放在应用程序文件中。您可以将它们放在单独的类中,从而分离关注点。
@SpringBootApplication
@EnableJms
public class Application {
    private static Random rand = new Random();

    @Bean
    DataSource dataSource() throws SQLException {
        OracleDataSource dataSource = new OracleDataSource();
        dataSource.setUser("yourusername");
        dataSource.setPassword("yourpassword");
        dataSource.setURL("jdbc:oracle:thin:@yourserver:1521:xe");
        dataSource.setImplicitCachingEnabled(true);
        dataSource.setFastConnectionFailoverEnabled(true);
        return dataSource;
    }    

    @Bean
    public QueueConnectionFactory connectionFactory() throws Exception {
        return AQjmsFactory.getQueueConnectionFactory(dataSource());
    }

    @Bean
    public JmsTemplate jmsTemplate() throws Exception {
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(connectionFactory());
        jmsTemplate.setMessageConverter(jacksonJmsMessageConverter());
        return jmsTemplate;
    }

    @Bean
    public JmsListenerContainerFactory<?> myJMSListenerFactory(QueueConnectionFactory connectionFactory,                                                      DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        //  factory.setConcurrency("15-20");
        factory.setMessageConverter(jacksonJmsMessageConverter());
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
        for (int i = 0; i < 10; i++) {
            int waitSecs = rand.nextInt(3);
            jmsTemplate.convertAndSend("YourQueueName", new Email("info@example.com", "Hello " + i, waitSecs));
        }
    }
}

第二步 - 创建JMS监听器

@Component
public class Receiver {
    @JmsListener(destination = "YourQueueName", containerFactory = "myJMSListenerFactory")
    public void receiveEmail(Email email) {
        System.out.println("Received <" + email + ">");
    }
}

3 - Maven和Oracle

您可以单独将oracle6或oracle7 jar文件添加到您的lib路径中,如此文章所示。

其余的Mavan文件非常标准。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

4 - 业务对象。像电子邮件这样的对象是您的业务领域POJO(普通Java对象)。我不会在这里放它们。

@Testing,这个工作就像魅力一样;-)


2

我认为你不需要改变myFactory方法本身,而是需要创建connectionFactory,它连接到Oracle队列。我有类似的配置,在开发中我使用artemis来运行我的JUNIT,在生产环境中我使用Oracle队列。下面是我定义的创建connectionFactory的类。

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.naming.Context;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.jndi.JndiTemplate;


/**
 * @author Karthik Prasad
 * @since 1.0.0.0
 *        <p>
 *        Configuration file for weblogic JMS connection
 */
@Configuration
@EnableJms
@ConfigurationProperties(prefix = "spring.wls.jms")
@ConditionalOnProperty(prefix = "spring.wls.jms", name = "url")
public class WLSJmsConfiguration {

    /**
     * SJ4J Log instance
     */
    private static final Logger LOG = LoggerFactory.getLogger(WLSJmsConfiguration.class);

    /**
     * provider url
     */
    private String url;
    /**
     * username of weblogic server using which JNDI connection will be
     * established
     */
    private String username;
    /**
     * password of weblogic server using which JNDI connection will be
     * established
     */
    private String password;
    /**
     * JMS Connection factory name configured in weblogic server
     */
    private String connectionFactoryName;

    /**
     * Name of destination queue
     */
    private String targetQueue;

    /**
     * The Response Queue
     */
    private String replyQueue;


    /**
     * URL to access weblogic Connectionfactory, property is set from properties
     * file
     * 
     * @see ConfigurationProperties
     * @param password
     *            weblogic url to JNDI
     */
    public void setUrl(final String url) {
        this.url = url;
    }

    /**
     * username to access weblogic queue, property is set from properties file
     * 
     * @see ConfigurationProperties
     * @param username
     *            weblogic username to access queue
     */
    public void setUsername(final String username) {
        this.username = username;
    }

    /**
     * Password to access weblogic queue, property is set from properties file
     * 
     * @see ConfigurationProperties
     * @param password
     *            weblogic password to access queue
     */
    public void setPassword(final String password) {
        this.password = password;
    }

    /**
     * Setter of connection factory name, property is set from properties file
     * 
     * @see ConfigurationProperties
     * @param connectionFactoryName
     *            ConnectionFactory from properties file
     */
    public void setConnectionFactoryName(final String connectionFactoryName) {
        this.connectionFactoryName = connectionFactoryName;
    }

    /**
     * Setter for {@link #targetQueue}
     * 
     * @param targetQueue
     *            the targetQueue to set
     */
    public void setTargetQueue(final String targetQueue) {
        this.targetQueue = targetQueue;
    }

    /**
     * @param replyQueue
     *            the replyQueue to set
     */
    public void setReplyQueue(final String replyQueue) {
        this.replyQueue = replyQueue;
    }


    /**
     * Get JNDI properties from properties file
     * 
     * @return list of Weblogic jndi properties
     */
    private Properties getJNDiProperties() {

        final Properties jndiProps = new Properties();
        LOG.debug("Initializing JndiTemplate");
        LOG.debug("Url is {}", url);
        jndiProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        jndiProps.setProperty(Context.PROVIDER_URL, url);
        if (username != null && !username.isEmpty()) {
            jndiProps.setProperty(Context.SECURITY_PRINCIPAL, username);
        }
        if (password != null && !password.isEmpty()) {
            jndiProps.setProperty(Context.SECURITY_CREDENTIALS, password);
        }
        return jndiProps;

    }

    /**
     * Create JndiTemplate for target weblogic server from provided JNDI
     * properties
     * 
     * @return Bean of Jndi Template
     */
    @Bean
    public JndiTemplate jndiTemplate() {
        final JndiTemplate jndiTemplate = new JndiTemplate();
        jndiTemplate.setEnvironment(getJNDiProperties());
        return jndiTemplate;
    }

    /**
     * Creates instance of Jndi Object Factory bean from Jndi Template
     * 
     * @param jndiTemplate
     *            Jndi Template for weblogic server
     * @return Bean of JndiObject Factory
     */
    @Bean(name = "jmsJndiConnectionFactory")
    public JndiObjectFactoryBean jndiObjectFactoryBean(final JndiTemplate jndiTemplate) {

        final JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        LOG.debug("Creating Weblogic JMS connection factory");
        jndiObjectFactoryBean.setJndiTemplate(jndiTemplate);
        // connectionFactory name.
        LOG.debug("ConnectoinFactory Name is {}", connectionFactoryName);
        jndiObjectFactoryBean.setJndiName(connectionFactoryName);
        return jndiObjectFactoryBean;

    }

    /**
     * Create Jms Connection factory from Jndi Objectfactory
     * 
     * @param jndiObjectFactoryBean
     *            Jndi Object factory bean
     * @return Returns Jms Connection factory Bean
     */
    @Bean(name = "jmsWlsConnectionFactory")
    public ConnectionFactory jmsConnectionFactory(final JndiObjectFactoryBean jndiObjectFactoryBean) {
        final ConnectionFactory connectionFactory = (ConnectionFactory) jndiObjectFactoryBean.getObject();
        LOG.debug("ConnectoinFactory is null? {}", connectionFactory == null);
        return connectionFactory;
    }

    /**
     * Wrap Weblogic Connection Factory around caching factory
     * 
     * @return
     */
    @Bean(name = "jmsConnectionFactory")
    @Primary
    public ConnectionFactory connectionFactoryProxy() {
        final CachingConnectionFactory jmsConnectionFactory = new CachingConnectionFactory(
                (ConnectionFactory) appContext.getBean("jmsWlsConnectionFactory"));
        jmsConnectionFactory.setCacheProducers(true);
        jmsConnectionFactory.setSessionCacheSize(20);
        return jmsConnectionFactory;
    }

    /**
     * The instance of Target Queue retrieved from JNDI, this bean is created in
     * dev profile, where one want to run the project in standalone mode but
     * want to connect to Weblogic Server
     * 
     * @return Bean of target queue instance
     */
    @Bean
    public Destination jmsQueueName() {

        final JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiTemplate(jndiTemplate());
        jndiObjectFactoryBean.setJndiName(targetQueue); // queue name
        return (Destination) jndiObjectFactoryBean.getObject();
    }

    /**
     * Create DestinationResolver to resolve QueueName
     * 
     * @return Instance of JNDI Destination Resolver
     */
    private DestinationResolver destinationResolver() {
        final JMSDestinationResolver destinationResolver = new JMSDestinationResolver();
        final JndiHelper jndiHelper = new JndiHelper(getJNDiProperties());
        destinationResolver.setJndiTemplate(jndiHelper);
        return destinationResolver;
    }

}

应用程序属性文件。
spring.wls.jms.url=t3://server01:8001,server02:8003
spring.wls.jms.username=weblogic
spring.wls.jms.password=password
spring.wls.jms.connectionFactoryName=connectionFactory Name
spring.wls.jms.targetQueue=queue_name
spring.wls.jms.replyQueue=queue_name

您需要将wlthint3client添加到您的类路径中。我从 <weblogic_home>\wlserver\server\lib 获取了该 jar 包,并创建了一个 maven 依赖项来使用该 jar 包并推送到我的本地仓库,然后将其作为依赖项添加到项目中。

    <dependency>
        <groupId>com.oracle.weblogic</groupId>
        <artifactId>wlthint3client</artifactId>
        <version>12.2.1</version>
        <scope>provided</scope> <!-- comment out this if you are deploying on tomcat or running the application standalone -->
    </dependency>

感谢您的回答。对于使用WebLogic的所有人都非常有用。但是,我如何在不需要WebLogic的情况下连接到Oracle Advanced Queueing(AQ)呢? 那么,在Spring Boot Oracle AQ中,与JMS示例中的ActiveMQ代码相当的是什么呢?请参见Spring Boot入门JMSGithub上的spring-boot-sample-activemq示例 - dhmc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接