EAR工程在jboss(wildfly)里的结构以及class loading关系

EAR , WAR ,JAR

EAR , WAR ,JAR 实际上都可以看成是文件夹,只是里面的组成规则不一样而已

  • WAR 工程结构
 - META-INF
 - WEB-INF
     - classes
     - lib     放着各种各样的jar       
     - jboss-web.xml (如果部署到tomcat下则不需要这个,这个可以覆盖 web.xml里的配置)
     - web.xml(一般配置servlet,servlet3.x后提供了插件形式,通过spi来发现)
  • EAR 工程结构
 - lib   放着各种各样的jar ,这些jar会被各种war工程共享
 - war (demo) 
 - META-INF

EAR在eclipse的组织形式

例子

myear里包含了demo.war,demo.war里的某个controller要依赖 ear-jar.jar里的AppService类,结构如下

  - ear-jar   jar工程 
  - demo      web工程 
  - myear     ear工程

demo web工程

@RestController
public class SimpleController {
	@PostMapping("/test")
	public String test(@RequestBody SimpleReq req){
	    //AppService是ear-jar
		return AppService.hello("rechard");
	}
}

demo web工程里虽然用到ear-jar,但scope是provided。这样的话在发布到jboss里后demo这个war的/META-INF/lib目录下的是不包含ear-jar.jar的

<dependency>
	<groupId>rechard.learn.ear</groupId>
	<artifactId>ear-jar</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<scope>provided</scope>
</dependency>

ear-jar jar工程

public class AppService {
    public static String hello( String name ){
        return "Hello World! "+ name ;
    }
}

my-ear 工程
application.xml 里描述的关系对应了eclipse里下面图
在这里插入图片描述

这样的话在发布到jboss里后,demo这个war的/META-INF/lib目录下的是不包含ear-jar.jar的,而ear-jar.jar会在myear/lib里。
结构如下:

myear.ear
  - demo.war
  - lib
    - ear-jar.jar
  - META-INF
    - application.xml

访问https://127.0.0.1:9444/demo/test 工程能正常运行。
也就是说myear下的lib下jar会被所有的war共享。
这样的好处是假如在myear 里有多个war工程,多个工程可以共享lib下的jar。

现在把myear.ear/lib/ear-jar.jar包去掉后,重新部署
再次访问就报 java.lang.NoClassDefFoundError: rechard/learn/service/AppService

如果将provided去掉后

<dependency>
	<groupId>rechard.learn.ear</groupId>
	<artifactId>ear-jar</artifactId>
	<version>0.0.1-SNAPSHOT</version>
    <!--去掉下面的 scope-->
	<!--<scope>provided</scope>-->
</dependency>

重新发布又可以正常访问
因为工程 demo/lib下有了,结构如下

myear.ear
  - demo.war
    -WEB-INF
     -lib
       -ear-jar.jar
  - META-INF
    - application.xml

详细可以看最后面 wildFly开发者指南1.3 class加载的优先级

假如一个类在myear/lib和demo/META-INF/lib都有,哪个会生效

将ear-jar拷贝一份命名成 ear-jar2后,让demo依赖于ear-jar2,ear-jar则发布到 myear/lib下,其中AppService 在2个jar里不同
ear-jar2里

public class AppService {
    public static String hello( String name ){
        return "Hello ear! "+ name ;
    }
}

ear-jar里

public class AppService {
    public static String hello( String name ){
        return "Hello world! "+ name ;
    }
}

demo里的pom.xml

<dependency>
	<groupId>rechard.learn.ear</groupId>
	<artifactId>ear-jar2</artifactId> <!--这里指向了ear-jar2-->
	<version>0.0.1-SNAPSHOT</version>	
</dependency>

myear的关系如下
在这里插入图片描述
实验后发现ear-jar2生效,至此结论是
如果类相同则先加载本级的lib下,如果没有则去找ear/lib下的jar

详细可以看最后面 wildFly开发者指南1.3 class加载的优先级

如果不把共享jar放在myear/lib下会怎么样?

首先让demo工程里依赖ear-jar 的scope为provided
demo下的pom.xml

<dependency>
	<groupId>rechard.learn.ear</groupId>
	<artifactId>ear-jar</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<scope>provided</scope>
</dependency>

在myear将ear-jar.jar放在非 lib目录下(对比原来是 lib/ear-jar.jar)

再次报java.lang.NoClassDefFoundError: rechard/learn/service/AppService

如何解决上面问题—方案1

myear/application.xml 里将ear-jar.jar配成一个module
在这里插入图片描述

由于myear/jboss_deploymnets_structure.xml里配置了
<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
其实不配默认也是false
所以ear-jar.jar可以默认被其他的war访问到
关于<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
可以看最后的wildFly开发者指南1.5

而如果不把这个 jar包装成module,是不会被加载到的,即使是在ear里而不放在 lib下

如何解决上面问题—方案2

通过在jboss-deployment-structure.xml里指定denpendcy

<?xml version="1.0" encoding="utf-8" ?>
<jboss-deployment-structure
        xmlns="urn:jboss:deployment-structure:1.3">
	<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
   <!--jboss-deployment-structure.xml如果是在ear包里,
     描述的是ear的关系,如果在war包里,则描述的是war包的关系-->
   <deployment>
       <dependencies>
          <module name="deployment.ear-jar" />
       </dependencies>
   </deployment>
 <!--在war工程里指定依赖-->  
 <sub-deployment name="demo-0.0.1-SNAPSHOT.war">
    <dependencies>
      <module name="deployment.ear-jar" />
    </dependencies>  
  </sub-deployment>
 <!--定义一个额外的module-->		
 <module name="deployment.ear-jar" >
    <resources>
     <resource-root path="ear-jar.jar" >
     </resource-root>
    </resources>
  </module>
	 
</jboss-deployment-structure>

注意,需要在前面加上 deployment前缀,如果不加就会报如下错误
在这里插入图片描述

更详细的可以看最后的wildFly开发者指南1.8

boss CLI 命令行接口学习

standalone.xml里有

 <management-interfaces>
            <native-interface security-realm="ManagementRealm">
                <socket-binding native="management-native"/>
            </native-interface>
            <http-interface security-realm="ManagementRealmHTTPS">
                <socket-binding https="management-https"/>
            </http-interface>
</management-interfaces>

 <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="management-native" interface="management" port="${jboss.management.native.port:9999}"/>
  </socket-binding-group>   

所以连接命令:
jboss-cli.bat --controller=127.0.0.1:9999 --connect --gui
通过图形化界面显示

WildFly开发者指南(WildFly Developer guide)摘抄

官网url

1.3 class加载的优先级

  1. System Dependencies - These are dependencies that are added to the module automatically by the container, including the Jakarta EE api’s.

  2. User Dependencies - These are dependencies that are added through jboss-deployment-structure.xml or through the Dependencies: manifest entry.

  3. Local Resource - Class files packaged up inside the deployment itself, e.g. class files from WEB-INF/classes or WEB-INF/lib of a war.

  4. Inter deployment dependencies - These are dependencies on other deployments in an ear deployment. This can include classes in an ear’s lib directory, or classes defined in other ejb jars.

总结:
优先级由高到低是
-> System Dependencies
-> jboss-deployment-structure.xml 指定的依赖或manifest.mf里的Dependencies:
-> WEB-INF/classes 或WEB-INF/lib
-> ear/lib

上面的实验 可以从这里找到依据

1.5. EAR Class Loading

wildfly 里将一个个的工程的看成一个moudle,比如ear,war,jar等等

ear 包里有多个模块。模块和模块之间是否能互相访问class呢?答案如下
Ear deployments are multi-module deployments. This means that not all classes inside an ear will necessarily have access to all other classes in the ear, unless explicit dependencies have been defined.
By default the EAR/lib directory is a single module, and every WAR or EJB jar deployment is also a separate module.
EAR/lib 是个单独的模块,而其他在ear里war和EJB jar都是一个独立的模块

Sub deployments (wars and ejb-jars) always have a dependency on the parent module, which gives them access to classes in EAR/lib, however they do not always have an automatic dependency on each other.
ear里的war和ejb-jar工程是依赖于父类的模块的,这样位于ear/lib里的class他们都能访问到。但他们之间是不自动依赖的
This behaviour is controlled via the ear-subdeployments-isolated setting in the ee subsystem configuration:

<subsystem xmlns="urn:jboss:domain:ee:1.0" >            
  <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
</subsystem>

By default this is set to false, which allows the sub-deployments to see classes belonging to other sub-deployments within the .ear.
默认是设成false,这样就能相互访问到

For example, consider the following .ear deployment:
myapp.ear
|
|— web.war
|
|— ejb1.jar
|
|— ejb2.jar
If the ear-subdeployments-isolated is set to false, then the classes in web.war can access classes belonging to ejb1.jar and ejb2.jar. Similarly, classes from ejb1.jar can access classes from ejb2.jar (and vice-versa).

如果设成false, web.war就能访问到ejb1.jar, ejb2.jar 和ejb1.jar之间就能相互访问

The ear-subdeployments-isolated element value has no effect on the isolated classloader of the .war file(s). i.e. irrespective of whether this flag is set to true or false, the .war within a .ear will have a isolated classloader and other sub-deployments within that .ear will not be able to access classes from that .war. This is as per spec.
这个参数对于war之间是不起作用的,war之间不能相互范文到,

If the ear-subdeployments-isolated is set to true then no automatic module dependencies between the sub-deployments are set up. User must manually setup the dependency with Class-Path entries, or by setting up explicit module dependencies.

1.6. Global Modules

statandalon.xml/domain.xml里的配置都是一些公共的配置

比如在 上面再statandalon.xml/domain.xml的配置就会应用到所有的deployment

1.8. JBoss Deployment Structure File
jboss-deployment-structure.xml is a JBoss specific deployment descriptor that can be used to control class loading in a fine grained manner.
jboss-deployment-structure.xml 是jboss 特定用来描述部署的配置
It should be placed in the top level deployment, in META-INF (or WEB-INF for web deployments). It can do the following:
可以放在META-INF (WEB-INF)包含以下关系
Prevent automatic dependencies from being added
Add additional dependencies
Define additional modules
Change an EAR deployments isolated class loading behaviour
Add additional resource roots to a module

<jboss-deployment-structure>
  <!-- Make sub deployments isolated by default, so they cannot see each others classes without a Class-Path entry -->
  <ear-subdeployments-isolated>true</ear-subdeployments-isolated>
  <!-- This corresponds to the top level deployment. For a war this is the war's module, for an ear -->
  <!-- This is the top level ear module, which contains all the classes in the EAR's lib folder     -->
  <deployment>
     <!-- exclude-subsystem prevents a subsystems deployment unit processors running on a deployment -->
     <!-- which gives basically the same effect as removing the subsystem, but it only affects single deployment -->
     <exclude-subsystems>
        <subsystem name="resteasy" />
    </exclude-subsystems>
    <!-- Exclusions allow you to prevent the server from automatically adding some dependencies     -->
    <exclusions>
        <module name="org.javassist" />
    </exclusions>
    <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
    <dependencies>
      <module name="deployment.javassist.proxy" />
      <module name="deployment.myjavassist" />
      <!-- Import META-INF/services for ServiceLoader impls as well -->
      <module name="myservicemodule" services="import"/>
    </dependencies>
    <!-- These add additional classes to the module. In this case it is the same as including the jar in the EAR's lib directory -->
    <resources>
      <resource-root path="my-library.jar" />
    </resources>
  </deployment>
  <sub-deployment name="myapp.war">
    <!-- This corresponds to the module for a web deployment -->
    <!-- it can use all the same tags as the <deployment> entry above -->
    <dependencies>
      <!-- Adds a dependency on a ejb jar. This could also be done with a Class-Path entry -->
      <module name="deployment.myear.ear.myejbjar.jar" />
    </dependencies>
    <!-- Set's local resources to have the lowest priority -->
    <!-- If the same class is both in the sub deployment and in another sub deployment that -->
    <!-- is visible to the war, then the Class from the other deployment will be loaded,  -->
    <!-- rather than the class actually packaged in the war. -->
    <!-- This can be used to resolve ClassCastExceptions  if the same class is in multiple sub deployments-->
    <local-last value="true" />
  </sub-deployment>
  <!-- Now we are going to define two additional modules -->
  <!-- This one is a different version of javassist that we have packaged -->
  <module name="deployment.myjavassist" >
    <resources>
     <resource-root path="javassist.jar" >
       <!-- We want to use the servers version of javassist.util.proxy.* so we filter it out-->
       <filter>
         <exclude path="javassist/util/proxy" />
       </filter>
     </resource-root>
    </resources>
  </module>
  <!-- This is a module that re-exports the containers version of javassist.util.proxy -->
  <!-- This means that there is only one version of the Proxy classes defined          -->
  <module name="deployment.javassist.proxy" >
    <dependencies>
      <module name="org.javassist" >
        <imports>
          <include path="javassist/util/proxy" />
          <exclude path="/**" />
        </imports>
      </module>
    </dependencies>
  </module>
</jboss-deployment-structure>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值