JBoss5 部署原理

本文将尝试解答以下几个问题:

1. JBoss5内核是如何部署的?
2. JBoss5部署体系发生了哪些变化?
3. 部署单元怎么被指定的deployer部署?
4. 热部署是如何实现的?

一、JBoss5内核的部署


JBoss5的内核是重新设计的Microcontainer,定制了一个ProfileServiceBootstrap用于启动Microcontainer。

bootstrap启动后,通过BasicXMLDeployer布署conf/bookstrap-beans.xml

在jboss5中使用XmlBinding组件解析bootstrap-beans.xml,xmlbinding组件通过schema定义文件将对象序列化为xml文件或反之,
通过反序列化得到一个AbstractKernelDeployment对象,它包含了所有Bean组件的元数据AbstractBeanMetaData;

然后通过KernelController安装Bean,并依次调用create, start方法,通过配置文件可以指定create和start方法的名称。

在bootstrap-beans中声明了一个主部署器MainDeployer,它包含一些内置的deployer,和一些StructureDeployer,它们的说明如下:

  WARStructure:处理WAR结构;
  JARStructure:处理JAR结构,包括zip, ear, jar, rar, war, sar, har, aop, deployer, beans
  FileStrucutre:处理File结构,包括-service.xml, -beans.xml, -ds.xml, -aop.xml结尾的文件;

  AspectDeployer:解析-aop.xml文件,

  BeanDeployer:解析-beans.xml文件,得到KernelDeployment对象;
  KernelDeploymentDeployer:将KernelDeployment中的BeanMetaData添加到DeploymentUnit;
  BeanMetaDataDeployer:将BeanMetaData安装到Microcontainer中。

  SARDeployer:解析-service.xml文件,得到ServiceDeployment对象;
  ServiceDeploymentDeployer:将ServiceDeployment中的ServiceMetaData添加到DeploymentUnit;
  ServiceDeployer:将ServiceMetaData安装到Microcontainer中,并启动它。

在bootstrap-beans中还声明了三个文件扫描器和一个热部署扫描器

VFSBootstrapScanner:扫描conf/jboss-service.xml;
VFSDeployerScanner:扫描deployers文件夹;
VFSDeploymentScanner:扫描deploy文件夹;

HDScanner:热部署扫描器。

二、JBoss5部署体系的变化


相对于JBoss4的部署体系,JBoss5的部署结构发生的非常大的变化,它完全是一个新的部署体系了。

我们知道在jboss4中,deployer有个accept方法来决定是否能接受部署,在JBoss5中,没用延用这种方式,一个可能的原因是Annotation的大量使用在简化部署描述文件的同时,增加了部署的难度,在很多时候我们的服务组件需要多个Deployer对它进行部署。
举个简单的例子,我们在服务组件上使用了AOP Annotation,那么这时服务组件应该由SARDeployer和AspectDeployer都进行部署。



 

三、部署流程


这里以部署conf/jboss-service.xml为例来说明部署的过程,

1. 扫描

在bootstrap-beans.xml中声明的VFSBootstrapScannerImpl用于扫描conf/jboss-service.xml并创建DeploymentContext
// VFSBootstrapScannerImpl.add
    DeploymentContext deployment = new AbstractDeploymentContext(file);
    if( !profile.hasDeployment(deployment.getName(), DeploymentPhase.BOOTSTRAP) )
        profile.addDeployment(deployment, DeploymentPhase.BOOTSTRAP);
  profile为当前配置实例,与启动jboss时指定的配置是对应的。

2. 装载profile

// ProfileServiceBootstrap.loadProfile
    Collection<DeploymentContext> boostraps = profile.getDeployments(DeploymentPhase.BOOTSTRAP);
    for (DeploymentContext d : boostraps) {
       deployer.addDeploymentContext(d);
       if (first == null)
          first = d;
    }
    deployer.process();

这里的deployer为主部署器MainDeployer,

addDeploymentContext方法有两个重要的操作:datermineStructure和addContext
datermineStructure:分析结构;
addContext:创建DeploymentUnit;

3. 开始部署

// MainDeployerImpl.java
   public Collection<DeploymentContext> process(ProcessMode mode)
   {
      for (int i = 0; i < theDeployers.length; ++i)
      {
         Deployer deployer = theDeployers[i];
 
         for (DeploymentContext context : deployContexts)
         {        
            context.getTransientAttachments().addAttachment(ProcessMode.class, mode);
            Set<DeploymentContext> components = context.getComponents();
            prepareDeploy(deployer, context, components);
            commitDeploy(deployer, context, components);
         }
      }
   }
   MainDeployer遍历所有已注册的Deployer,并依次用它们去部署context;

   private void commitDeploy(Deployer deployer, DeploymentContext context,
    Set<DeploymentContext> components)     
   {
      DeploymentContext[] theComponents = null;
      if (components != null && components.isEmpty() == false)
         theComponents = components.toArray(new DeploymentContext[components.size()]);
     
      DeploymentUnit unit = context.getDeploymentUnit();
      deployer.commitDeploy(unit);

      if (theComponents != null)
      {
         for (int i = 0; i < theComponents.length; ++i)
         {
            Set<DeploymentContext> componentComponents = theComponents[i].getComponents();
            commitDeploy(deployer, theComponents[i], componentComponents);
         }
      }
   }
   因为DeploymentContext采用的是父子结构,所以整个部署也采用递归的方式进行部署;


那么如何确定由哪个部署器来进行部署呢?

下面是jboss-service.xml的部署流程

//  AspectDeployer.java (.skip.)
   public void deploy(DeploymentUnit unit)
   {
      List<VirtualFile> files = unit.getMetaDataFiles(null, "-aop.xml");

      if (isAopArchiveOrFolder(unit)) {
         // 部署采用Annotation方式的AOP定义;
         deployAnnotations(unit);
      }
     
      if (files.size() > 0) {
         // 部署采用xml文件的AOP定义;
         deployXml(unit, files);
      }
   }

//  BeanDeployer.java (.skip.)
   public void deploy(DeploymentUnit unit)
   {
      // 为"-beans.xml"结尾的文件创建元数据;
      createMetaData(unit, null, "-beans.xml");
   }

   // AbstractParsingDeployer.java
      protected void createMetaData(DeploymentUnit unit,
          String name, String suffix, String key)
      {
         // Create it
         if (suffix == null)
            result = parse(unit, name, result);
         else
            result = parse(unit, name, suffix, result);
         // Add the associated deployer type if there is a result
         if( result != null )
            unit.getTypes().add(getType());
      
         // Doesn't exist
         if (result == null)
            return;
     
         // 注册到部署单元中,给后续的部署器使用
         unit.addAttachment(key, result, getDeploymentType());
      }

  

// KernelDeploymentDeployer.java (.skip.)

  

// BeanMetaDataDeployer.java (.skip.)
   // AbstractSimpleRealDeployer.java
   public void deploy(DeploymentUnit unit)
   {
      T deployment = unit.getAttachment(getDeploymentType());
      if (deployment != null)
      {
         // Set the deployer type
         unit.getTypes().add(getType());
         deploy(unit, deployment);
      }
   }
   这里的getDeploymentType()为BeanMetaData.class

  

// SARDeployer.java (.use.)
   public void deploy(DeploymentUnit unit)
   {
      // 为"-service.xml"结尾的文件创建元数据,与本例的jboss-service.xml是匹配的。
      createMetaData(unit, null, "-service.xml");
   }

   // AbstractParsingDeployer.java
   protected void createMetaData(DeploymentUnit unit,
    String name, String suffix, String key)
   {
      // Create it
      if (suffix == null)
         result = parse(unit, name, result);
      else
         result = parse(unit, name, suffix, result);
      // Add the associated deployer type if there is a result
      if( result != null )
         unit.getTypes().add(getType());
     
      // Doesn't exist
      if (result == null)
         return;
     
      // 注册到部署单元中,给后续的部署器使用
      unit.addAttachment(key, result, getDeploymentType());
   }

   protected ServiceDeployment parse(DeploymentUnit unit,
        VirtualFile file, Document document)
   {
      ServiceDeploymentParser parser = new ServiceDeploymentParser(document);
      // 创建ServiceDeployment;
      ServiceDeployment parsed = parser.parse();
      String name = file.toURI().toString();
      parsed.setName(name);

      List<ServiceDeploymentClassPath> classPaths = parsed.getClassPaths();
      if (classPaths != null)
         processXMLClasspath(unit.getDeploymentContext(), classPaths);

      LoaderRepositoryConfig config = parsed.getLoaderRepositoryConfig();
      if (config != null)
         unit.addAttachment(LoaderRepositoryConfig.class.getName(), config);
      return parsed;
   }

  

// ServiceClassLoaderDeployer.java (.use.)
   public void deploy(DeploymentUnit unit)
   {
      ClassLoaderFactory factory = unit.getAttachment(ClassLoaderFactory.class);
      if( factory == null )
         factory = this;
      unit.createClassLoader(factory);
   }

  

// ServiceDeploymentDeployer.java (.use.)
  
   // AbstractComponentDeployer.java
   public void deploy(DeploymentUnit unit)
   {
      super.deploy(unit);
      deployComponents(unit);
   }

   // AbstractRealDeployer.java
   public void deploy(DeploymentUnit unit)
   {
      Set<? extends T> deployments = unit.getAllMetaData(deploymentType);
      for (T deployment : deployments)
         visitor.deploy(unit, deployment);
   }
   这里的deploymentType为ServiceDeployment.class,所以是有值的。

   // ServiceDeploymentVisitor.java
   public void deploy(DeploymentUnit unit,
      ServiceDeployment deployment)
   {
      List<ServiceMetaData> services = deployment.getServices();
      if (services == null)
      {
         Element config = deployment.getConfig();

         // 这里才真正开始解析jboss-service.xml中的mbean元素,
         // 每个mbean元素对应一个ServiceMetaData
         ServiceMetaDataParser parser = new ServiceMetaDataParser(config);
         services = parser.parse();
         deployment.setServices(services);
      }

      if (services == null || services.isEmpty())
         return;
           
      // 加入到部署单元中,
      // 服务组件也是一个部署单元,与root部署单元是父子关系。
      for (ServiceMetaData service : services)
         addServiceComponent(unit, service);
   }
  
   // AbstractComponentDeployer.java
   protected void deployComponents(DeploymentUnit unit)
   {
      Set<? extends C> components = unit.getAllMetaData(componentType);
      for (C component : components)
         compVisitor.deploy(unit, component);
   }
   这里的componentType为ServiceMetaData.class,没有值。

  

// ServiceDeployer.java (.use.)

   // AbstractSimpleRealDeployer.java
   public void deploy(DeploymentUnit unit)
   {
      T deployment = unit.getAttachment(getDeploymentType());
      if (deployment != null)
      {
         // Set the deployer type
         unit.getTypes().add(getType());
         deploy(unit, deployment);
      }
   }
   // 这里的getDeploymentType()为ServiceMetaData.class;

   // ServiceDeployer.java
   public void deploy(DeploymentUnit unit, ServiceMetaData deployment)
   {
      ObjectName name = deployment.getObjectName();

      // 查找class loader;
      ObjectName loaderName = deployment.getClassLoaderName();
      if (loaderName == null)
      {
         ClassLoader cl = unit.getClassLoader();
         if (cl != null && cl instanceof RepositoryClassLoader)
            loaderName = ((RepositoryClassLoader) cl).getObjectName();
         else
            loaderName = defaultClassLoader;
      }

      // 安装组件;
      controller.install(deployment, loaderName);

      ServiceContext context = controller.getServiceContext(name);
      if (context == null)
         throw new IllegalStateException("No context for " + name);

      try
      {
         // 组件创建,调用组件的create方法;
         create(context);
         try
         {
            // 组件启动,调用组件的start方法;
            start(context);
         }
         catch (Throwable t)
         {
            destroy(name);
            throw t;
         }
      }
      catch (Throwable t)
      {
         remove(name);
         throw t;
      }
   }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值