跳至主要内容

Annotations in JBoss Deployment

在我们书写EJB代码时,为了简化配置,我们使用了注解而不是xml配置文件。那么,JBoss(或者说Wildfly)是如何利用这些注解,在合适的时候调用了我们的代码呢?换句话说,jboss从启动到输出像这样的jndi设置信息的部署过程究竟发生了什么?今天我们就通过分析其源代码简单探讨一下这个问题。

从annotations讲起

在开发过程中, 我们也时常会在应用代码中会看到这些看上去比较奇怪的@开头的东西,例如@Override, @Deprecated。他们的作用到底是什么?又是如何实现的呢?我们稍稍介绍以一跟我们今天内容相关的背景。

注解,根据其寿命长短,可以分为三类:

  1. Source:只存在于源代码中,在编译后便被丢弃。所以说他的作用范围便是编译时。
  2. Class:在class文件中,但不在VM中。貌似没有什么卵用
  3. Runtime:一直存活到VM中,即可以通过反射获得注释信息(用大白话说就是,当你程序跑起来之后,还可以获取注解的内容)。

所以,联想到我们在使用EJB的过程:先写好源代码,再编译,再打包,再交给jboss部署,jboss再调用我们的代码。我们可以明白,诸如@Stateless, @EJB这样的注解都是第三类注解。

JBoss部署

在上面讲的使用EJB的过程中,jboss的部署其实还是一个黑盒,所以当我们把我们的jar包部署到JBoss时究竟发生了什么?
让我们通过源代码(org/jboss/as/server/deployment/Phase.java)把部署过程理一理:

/**
 * This phase creates the initial root structure.  Depending on the
 * service for this phase will ensure that the
 * deployment unit's initial root structure is available and accessible.
 * Upon entry, this phase performs the following actions:
 * <ul>
 * <li>The primary deployment root is mounted (during {@link #STRUCTURE_MOUNT})</li>
 * <li>Other internal deployment roots are mounted (during {@link #STRUCTURE_NESTED_JAR})</li>
 * </ul>
 */
STRUCTURE(null),
/**
 * This phase assembles information from the root structure to prepare
 * for adding and processing additional external
 * structure, such as from class path entries and other similar 
 * mechanisms.
 * Upon entry, this phase performs the following actions:
 * <ul>
 * <li>The root content's MANIFEST is read and made available during
 * {@link #PARSE_MANIFEST}.</li>
 * <li>The annotation index for the root structure is calculated during 
 * {@link #STRUCTURE_ANNOTATION_INDEX}.</li>
 * </ul>
 */
PARSE(null),
/**
 * In this phase parsing of deployment metadata is complete and the 
 * component may be registered with the subsystem.
 * This is prior to working out the components dependency and equivalent 
 * to the OSGi INSTALL life cycle.
 */
REGISTER(null),
/**
 * In this phase, the full structure of the deployment unit is made 
 * available and module dependencies may be assembled.
 * Upon entry, this phase performs the following actions:
 * <ul>
 * <li>Any additional external structure is mounted during {@link #XXX}</li>
 * </ul>
 */
DEPENDENCIES(null),
CONFIGURE_MODULE(null),
/**
 * Processors that need to start/complete before the deployment 
 * classloader is used to load application classes,
 * belong in the FIRST_MODULE_USE phase.
 */
FIRST_MODULE_USE(null),
POST_MODULE(null),
INSTALL(null),
CLEANUP(null),
;

当然,这只是对部署过程的概览,其实每一个步骤下都有许多小的步骤,非常复杂,要理解注解的角色,我们从jboss启动开始讲起。

首先JBoss启动–>注册processor->DeploymentUnitPhaseService.start()->processor.deploy()开始逐层调用各个步骤的processor以完成不同阶段的功能 – 下面列举了一些:

// create the index of annotations:读取类文件,抽象成Index对象
//(类似于class类,读取annotation,method,field。。。)
DeployerChainAddHandler.addDeploymentProcessor(SERVER_NAME, 
Phase.STRUCTURE, Phase.STRUCTURE_ANNOTATION_INDEX, new 
AnnotationIndexProcessor());

// create composite index:用list集中管理
DeployerChainAddHandler.addDeploymentProcessor(SERVER_NAME, Phase.PARSE,
 Phase.PARSE_COMPOSITE_ANNOTATION_INDEX, new CompositeIndexProcessor());

// process annotations:开始处理,解析
//(分成SessionBean,MessageDrivenBean分别处理)
processorTarget.addDeploymentProcessor(EJB3Extension.SUBSYSTEM_NAME, 
Phase.PARSE, Phase.PARSE_CREATE_COMPONENT_DESCRIPTIONS, new 
AnnotatedEJBComponentDescriptionDeploymentUnitProcessor(appclient));

// make jndi binding:注册JNDI,然后输出一段熟悉的注册信息(如下)
processorTarget.addDeploymentProcessor(EJB3Extension.SUBSYSTEM_NAME, 
Phase.POST_MODULE, Phase.POST_MODULE_EJB_JNDI_BINDINGS, new 
EjbJndiBindingsDeploymentUnitProcessor(appclient));
java:global/learnEJB/HelloBean!first.HelloBean
java:app/learnEJB/HelloBean!first.HelloBean
java:module/HelloBean!first.HelloBean
java:global/learnEJB/HelloBean!first.HelloBeanRemote
java:app/learnEJB/HelloBean!first.HelloBeanRemote
java:module/HelloBean!first.HelloBeanRemote
java:jboss/exported/learnEJB/HelloBean!first.HelloBeanRemote

Ref:

  1. RetentionPolicy.CLASS
  2. JBoss VFS

Written with StackEdit.

评论

此博客中的热门博文

Spring Boot: Customize Environment

Spring Boot: Customize Environment Environment variable is a very commonly used feature in daily programming: used in init script used in startup configuration used by logging etc In Spring Boot, all environment variables are a part of properties in Spring context and managed by Environment abstraction. Because Spring Boot can handle the parse of configuration files, when we want to implement a project which uses yml file as a separate config file, we choose the Spring Boot. The following is the problems we met when we implementing the parse of yml file and it is recorded for future reader. Bind to Class Property values can be injected directly into your beans using the @Value annotation, accessed via Spring’s Environment abstraction or bound to structured objects via @ConfigurationProperties. As the document says, there exists three ways to access properties in *.properties or *.yml : @Value : access single value Environment : can access multi

Elasticsearch: Join and SubQuery

Elasticsearch: Join and SubQuery Tony was bothered by the recent change of search engine requirement: they want the functionality of SQL-like join in Elasticsearch! “They are crazy! How can they think like that. Didn’t they understand that Elasticsearch is kind-of NoSQL 1 in which every index should be independent and self-contained? In this way, every index can work independently and scale as they like without considering other indexes, so the performance can boost. Following this design principle, Elasticsearch has little related supports.” Tony thought, after listening their requirements. Leader notice tony’s unwillingness and said, “Maybe it is hard to do, but the requirement is reasonable. We need to search person by his friends, didn’t we? What’s more, the harder to implement, the more you can learn from it, right?” Tony thought leader’s word does make sense so he set out to do the related implementations Application-Side Join “The first implementation

Implement isdigit

It is seems very easy to implement c library function isdigit , but for a library code, performance is very important. So we will try to implement it and make it faster. Function So, first we make it right. int isdigit ( char c) { return c >= '0' && c <= '9' ; } Improvements One – Macro When it comes to performance for c code, macro can always be tried. #define isdigit (c) c >= '0' && c <= '9' Two – Table Upper version use two comparison and one logical operation, but we can do better with more space: # define isdigit(c) table[c] This works and faster, but somewhat wasteful. We need only one bit to represent true or false, but we use a int. So what to do? There are many similar functions like isalpha(), isupper ... in c header file, so we can combine them into one int and get result by table[c]&SOME_BIT , which is what source do. Source code of ctype.h : # define _ISbit(bit) (1 << (