在我们书写EJB代码时,为了简化配置,我们使用了注解而不是xml配置文件。那么,JBoss(或者说Wildfly)是如何利用这些注解,在合适的时候调用了我们的代码呢?换句话说,jboss从启动到输出像这样的jndi设置信息的部署过程究竟发生了什么?今天我们就通过分析其源代码简单探讨一下这个问题。
从annotations讲起
在开发过程中, 我们也时常会在应用代码中会看到这些看上去比较奇怪的@开头的东西,例如@Override, @Deprecated。他们的作用到底是什么?又是如何实现的呢?我们稍稍介绍以一跟我们今天内容相关的背景。
注解,根据其寿命长短,可以分为三类:
- Source:只存在于源代码中,在编译后便被丢弃。所以说他的作用范围便是编译时。
- Class:在class文件中,但不在VM中。貌似没有什么卵用
- 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:
Written with StackEdit.
评论
发表评论