Activemq 启动分析

来源:互联网 发布:enum class java 编辑:程序博客网 时间:2024/05/01 00:01

Activemq 启动分析

 

Active的启动是从org.apache.activemq.console中的Main类中启动的。

 

启动中的命令模式

 

我这里传递参数如下:

 

-Xms1G -Xmx1G

-Djava.util.logging.config.file=logging.properties

-Dhawtio.realm=activemq

-Dhawtio.role=admins

-Dhawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal

 

-Dactivemq.home=F:\消息中间件\activeMQ\apache-activemq-5.8.02

-Dactivemq.base=F:\消息中间件\activeMQ\apache-activemq-5.8.02

-Dactivemq.conf=F:\消息中间件\activeMQ\apache-activemq-5.8.02\conf

-Dactivemq.data=F:\消息中间件\activeMQ\apache-activemq-5.8.02\data

-Djava.io.tmpdir=F:\消息中间件\activeMQ\apache-activemq-5.8.02\data\tmpstart

 

其中,app.runTaskClass(tokens);为main类调用命令模式,通过反射执行 shellCommand

String[] args = tokens.toArray(new String[tokens.size()]);

           Class<?> task = cl.loadClass(TASK_DEFAULT_CLASS);

            Method runTask = task.getMethod("main",new Class[] {

                String[].class, InputStream.class, PrintStream.class

            });

           runTask.invoke(task.newInstance(),args, System.in, System.out);

 

 

这里除了可以使用start命令之外,还有很多其他的命令可以使用:

 

·        activemq-admin stop

·        activemq-admin list

·        activemq-admin query

·        activemq-admin bstat

·        activemq-admin browse

在shellCommand中,有这样一个方法:

 

ArrayList<Command>getCommands() {

        ServiceLoader<Command> loader =ServiceLoader.load(Command.class);

        ArrayList<Command> rc = newArrayList<Command>();

        for( Command command: loader ) {

            rc.add(command);

        }

        return rc;

}

 

注意这个方法中的ServiceLoader.load(Command.class) 这是jdk提供的一个方法,用户加载实现了command接口的所有的实现类。

 

这里因为传递的是start,所以,会执行对应的 startCommand:

 

command.execute(tokens);

 

额,下面才是真正的启动的干货了。

 

Broker的组装

在执行startCommand中的runTask 方法的时候,会传递进入一个brokerURI数组。该数组就是activemq的核心配置文件。如果该数组为空,则会构建一个xbean:activemq.xml。否则取数组中的第一个为配置文件路径。

然后将URI传入brokerFactory中,并通过brokerFactory创建一个broker,并启动该broker。

 

broker = BrokerFactory.createBroker(configURI);

           broker.start();

 

 

那我们就来看看如何构建一个broker的。

 

BrokerFactoryHandler handler = createBrokerFactoryHandler(brokerURI.getScheme());

       BrokerService broker = handler.createBroker(brokerURI);

该方法返回值BrokerFactoryHandler 只是一个接口而已。他的实现类有PropertiesBrokerFactory ,DefaultBrokerFactory等,这里具体的实例到底是个什么类型的呢?

首先,根据brokerURI文件路径,判断出来是那种类型的配置文件。比如我们这里传入的brokerURI是xbean:activemq.xml

 

这里的加载方式比较有意思。主要加载方式是在org.apache.activemq.util中的FactoryFinder中实现的。

该factoryFinder中,有一个Map,维护了一个类表示和类之间的对应关系。

 

这里传递进来的是类标志,然后通过标志去加载对应的配置文件:META-INF/services/org/apache/activemq/broker/xbean 。

加载该类之后,也就通过反射,构建出了一个xbeanBrokerFactory了。

所以,构造broker的任务也是由 xbeanBrokerFactory来通过下面方法完成的

BrokerService broker =handler.createBroker(brokerURI);

 

其实activemq中,不少的配置都是借鉴了spring ioc思想的,所以xbean也是基于spring ioc构建。该类存在于activemq-spring jar中。

 

我们来看具体的代码:

 

ApplicationContext context =createApplicationContext(uri);

 

       BrokerService broker = null;

       try {

           broker = (BrokerService) context.getBean("broker");

       } catch (BeansException e) {

       }

 

       if (broker ==null) {

           // lets try findby type

           String[] names = context.getBeanNamesForType(BrokerService.class);

           for (int i = 0; i < names.length; i++) {

              String name = names[i];

              broker = (BrokerService) context.getBean(name);

              if (broker !=null) {

                  break;

              }

           }

       }

       if (broker ==null) {

           throw new IllegalArgumentException(

                  "Theconfiguration has no BrokerService instance for resource: "

                         + config);

       }

 

       SpringBrokerContext springBrokerContext = newSpringBrokerContext();

       springBrokerContext.setApplicationContext(context);

       springBrokerContext.setConfigurationUrl(uri);

       broker.setBrokerContext(springBrokerContext);

 

前面几行代码非常的简单。其实就是spring ioc的基本的应用。通过配置文件,或得到broker bean。

 

Spring 和mq整合部分:

 

这里不是重点,简单写一些:

在activemq.xml的配置文件中,有一下两个地方需要注意:

 

 

其中xsd是用于规范xml里面的内容和格式的。

 

下面的core就是每一个节点的意义了。

加载路径其实就是在jar包中的。对应路径如下:

 

其中,标红的哪一行就是说明了当有一个broker的时候,应该生成一个什么样的对象。

 

 

那么通过如上的分析,broker的结构就非常的清晰了。

BrokerService的启动

这里分成两部分处理,一部分是数据库持久化适配器的初始化

startPersistenceAdapter(startAsync);

还有一部分是broker 的启动 doStartBroker()

 

启动持久化适配器

 

doStartPersistenceAdapter()

 

在brokerService中,有个PersistenceAdapter属性

 

持久化适配器的启动就是通过persistenceAdapter的启动来完成的。这里,我以JDBCpersistenceAdapter为例分析一下;

JDBCPersistenceAdapter 继承 DataSourceServiceSupport 并实现了PersistenceAdapter 接口。其中,persistenceAdapter主要是定义了同数据存储层的操作行为。DataSourceServiceSupport 主要是提供了一个数据源,并且因为是一个service,所以有启动,终止等生命周期。

 

我们来看一下他的启动,启动主要是通过下面两个方法完成的

 

preStart():主要完成了对数据库的锁定

doStart():完成设置定期清理任务和构建消息审计

 

 

启动broker

 

主要是通过doStartBroker() 方法启动brokerService的。其中,启动brokerService包括启动所有终端,启动连接器等等。

 

首先,需要构建一个broker

 

regionBroker = newRegionBroker(this,getTaskRunnerFactory(), getConsumerSystemUsage(),destinationFactory,

                    destinationInterceptor,getScheduler(),getExecutor());

 

开启所有的连接器

startAllConnectors

 

启动某一个连接器

startTransportConnector

 

 

启动完毕之后,加入停止监听.注意这里的conuntDownLatch。他是juc中的一个线程控制类。在完成其他线程的任务之前,他可以一直等待。

final CountDownLatch shutdownLatch =new CountDownLatch(1);

            final ThreadjvmShutdownHook = new Thread() {

                publicvoid run() {

                    try {

                        broker.stop();

                    } catch (Exception e) {

                    }

                }

            };

 

            Runtime.getRuntime().addShutdownHook(jvmShutdownHook);

            broker.addShutdownHook(new Runnable() {

                publicvoid run() {

                    shutdownLatch.countDown();

                }

            });

 

            // The broker has stopped..

           shutdownLatch.await();

 

这里需要注意的是Runtime.getRuntime().addShutdownHook(jvmShutdownHook);

这里是在虚拟机中增加了一个关闭钩子。要关闭虚拟机的时候,这些钩子必须先关闭之后,jvm才能够关闭。并且,在brokerService中也增加了一个关闭钩子。BrokerService关闭的时候,计数器shutdownLatch会减少。从而使得shutdownLatch 停止等待,程序退出。

 

0 0
原创粉丝点击