Chapter 10. Running Aspectized Applications

This section will show you how to run JBoss AOP with standalone applications and how to run it integrated with the JBoss application server.

10.1. Loadtime, Compiletime and HotSwap Modes

There are 3 different modes to run your aspectized applications. Precompiled, loadtime or hotswap. JBoss AOP needs to weave your aspects into the classes which they aspectize. You can choose to use JBoss AOP's precompiler to accomplish this (Compiletime) or have this weavining happen at runtime either when the class is loaded (Loadtime) or after it (HotSwap).

Compiletime happens before you run your application. Compiletime weaving is done by using the JBoss AOP precompiler to weave in your aspects to existing .class files. The way it works is that you run the JBoss AOP precompiler on a set of .class files and those files will be modified based on what aspects you have defined. Compiletime weaving isn't always the best choice though. JSPs are a good instance where compiletime weaving may not be feasible. It is also perfectly reasonable to mix and match compile time and load time though. If you have load-time transformation enabled, precompiled aspects are not transformed when they are loaded and ignored by the classloader transformer.

Loadtime weaving offers the ultimate flexibility. JBoss AOP does not require a special classloader to do loadtime weaving, but there are some issues that you need to think about. The Java Virtual Machine actually has a simple standard mechanism of hooking in a class transformer through the -javaagent. JBoss AOP an additional load-time transformer that can hook into classloading via this standard mechanism.

Load-time weaving also has other serious side effects that you need to be aware of. JBoss AOP needs to do the same kinds of things that any standard Java profiling product needs to do. It needs to be able to process bytecode at runtime. This means that boot can end up being significantly slowed down because JBoss AOP has to do a lot of work before a class can be loaded. Once all classes are loaded though, load-time weaving has zero effect on the speed of your application. Besides boottime, load-time weaving has to create a lot of Javassist datastructure that represent the bytecode of a particular class. These datastructures consume a lot of memory. JBoss AOP does its best to flush and garbage collect these datastructures, but some must be kept in memory. We'll talk more about this later.

HotSwap weaving is a good choice if you need to enable aspects in runtime and don't want that the flow control of your classes be changed before that. When using this mode, your classes are instrumented a minimum necessary before getting loaded, without affecting the flow control. If any joinpoint becomes intercepted in runtime due to a dynamic AOP operation, the affected classes are weaved, so that the added interceptors and aspects can be invoked. As the previous mode, hot swap contains some drawbacks that need to be considered.

10.2. Regular Java Applications

JBoss AOP does not require an application server to be used. Applications running JBoss AOP can be run standalone outside of an application server in any standard Java application. This section focuses on how to run JBoss AOP applications that don't run in the JBoss application server.

10.2.1. Precompiled instrumentation

Running a precompiled aop application is quite similar to running a normal java application. In addition to the classpath required for your application you need to specify the files required for aop, which are the files in the distribution's lib/ folder.

As an alternative, you can replace all those jars by jboss-aop-single.jar, that bundles the libraries used by JBoss AOP with JBoss AOP class files in a single jar.

JBoss AOP finds XML configuration files in these two ways:

  • You tell JBoss AOP where the XML files are. Set the jboss.aop.path system property. (You can specify multiple files or directories separated by ':' (*nix) or ';' (Windows), i.e. -Djboss.aop.path=jboss-aop.xml;metadata-aop.xml) If you specify a directory, all aop.xml files will be loaded from there as well.
  • Let JBoss AOP figure out where XML files are. JBoss AOP will look for all XML files that match this pattern /META-INF/jboss-aop.xml. So, if you package your jars and put your JBoss AOP XML files within /META-INF/jboss-aop.xml, JBoss AOP will find these files.

If you are using annotated bindings (See Chapter "Annotated Bindings"), you must tell JBoss AOP which JARS or directories that may have annotated @Aspects. To do this you must set the jboss.aop.class.path system property. (You can specify multiple jars or directories separated by ':' (*nix) or ';' (Windows), i.e. -Djboss.aop.class.path=aspects.jar;classes)

So to run a precompiled AOP application, where your jboss-aop.xml file is not part of a jar, you enter this at a command prompt:

$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \
         -Djboss.aop.class.path=aspects.jar
         com.blah.MyMainClass
            

To run a precompiled AOP application, where your application contains a jar with a META-INF/jboss-aop.xml file, you would need to do this from the command-line:

$ java -cp=<classpath as described above> com.blah.MyMainClass
            

In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage:

$ run-precompiled classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
            

If your application is not in a jar with a META-INF/jboss-aop.xml file, you must specify the path to your *-aop.xml files in the -aoppath parameter, and if your class comtains aspects configured via annotations ( @Aspect etc.) you must pass in this classpath via the -aopclasspath parameter.

10.2.2. Loadtime

This section describes how to use loadtime instrumentation of classes with aop. The classes themselves are just compiled using Java, but are not precompiled with the aop precompiler. In the examples given if your classes are contained in a jar with a META-INF/jboss-aop.xml file, you would omit the -Djboss.aop.path system property.

The JVM has a pluggable way of defining a class transformer via the java.lang.instrument package. JBoss AOP uses this mechanism to weave aspects at class load time. Using loadtime weaving is really easy. All you have to do is define an additional standard switch on the Java command line. -javaagent:jboss-aop.jar. Here's how run an AOP application with loadtime instrumentation, where your jboss-aop.xml file is not part of a jar:

$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \
      -javaagent:jboss-aop.jar com.blah.MyMainClass
            

And to run an AOP application with loadtime instrumentation, where your application contains a jar with a META-INF/jboss-aop.xml file:

$ java -cp=<classpath as described above> -javaagent:jboss-aop.jar \
      com.blah.MyMainClass
            

In the /bin folder of the distribution we have provided batch/script files to make this easier. It includes all the aop libs for you, so you just have to worry about your files. The usage:

$ run-load classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
      com.blah.MyMainClass [args...]
            

The parameters have the same meaning as for the run-precompiled scripts.

If you invoke the previous java examples with ant, by using the ant java task, make sure that you set fork="true" in the ant java task. Failure to do so, causes the java task to execute in the same VM as ant which is already running. This means that the special classloader used to do the loadtime transformations does not replace the standard one, so no instrumentation takes place.

10.2.2.1. Loadtime using JRockit

JRockit 5+ supports the "normal" -javaagent switch.

10.2.2.2. Improving Loadtime Performance

JBoss AOP needs to do the same kinds of things that any standard Java profiling product needs to do. It needs to be able to process bytecode at runtime before a class is loaded. JBoss AOP has to do a lot of work before a class can be loaded. This means that boot time can end up being significantly slowed down. Once all classes are loaded though, load-time weaving has zero effect on the speed of your application.

Besides boottime, load-time weaving has to create a lot of Javassist datastructures that represent the bytecode of a particular class. These datastructures consume a lot of memory. JBoss AOP does its best to flush and garbage collect these datastructures, but some must be kept in memory. This section focuses on how you can improve the performance of Loadtime weaving.

Increase the Java Heapspace

In Java, when your application is getting close to eating up all of its memory/heapspace, the Java Garbage Collector starts to run more frequently and aggressively. When the GC starts running more often the performance of your application will suffer. JBoss AOP does its best to balance bootup speed vs. memory consumption, but it does require loading bytecode into Javassist datastructures so it can analyze and transform a class. For speed purposes, the datastructures are cached thus leading to the extra memory consumption. Javassist structures of non-transformed classes are placed a SoftReference cache, so they are GC'd when memory is running low. Transformed classes, however, are locked in the cache. Transformed classes are help in memory, as they may effect pointcut matching on classes that haven't been loaded yet.

To increase your Heap size, use the standard -Xmx switch.

Filtering

Filtering probably has the greatest effect on overall boot-time speed. If you've ever worked with a Java profiling product before, you probably noticed that it has an option to filter classes that you are not interested in profiling. This can speed up performance of the tool. JBoss AOP has to analyze every class in the system to make sure it does not need to be transformed. THis is one reason why load-time weaving can be so slow. You can give JBoss AOP a lot of help by specifying sets of classes that do not need to be transformed.

To enable filtering, you can use the jboss.aop.exclude System Property. This System Property is a comma delimited list. The strings in the list can be package names and/or classnames. Packages/classes within this list will ignored by JBoss AOP. You can use the wildcard * in place of a classname, this will then exclude all classes. No other wildcards are supported.

                     java -Djboss.aop.exclude=org.jboss,org.apache ...
                  

There is also a mirror opposite of exclude. The System Property jboss.aop.include overrides any thing specified with exclude.

Include ignored annotations

To improve the startup time of JBoss AOP all invisible annotations (invisible annotations are all annotations that are not annotated with @Retention(RetentionPolicy.RUNTIME)) are ignored by default. To include them use the system property jboss.aop.invisible.annotations to add packages that will be included, or add "*" to include all.

                      java -Djboss.aop.include.annotations=com.foo.bar,org.my.company
                    

To include all:

                      java -Djboss.aop.include.annotations=*
                    
Turn off optimizations

To increase overall runtime performance, JBoss AOP has to dynamically create a lot of extra code. If you turn off these optimizations, JBoss AOP can weave a bit quicker. There is a good chance, depending on your application that you will not even notice that these optimizations are turned off. See Chapter 14, Instrumentation Modes for how to switch between weaving modes.

Turn off pruning

JBoss AOP tries to aggressive prune cached Javassist structures. This may, may not have a tiny effect on performance. The jboss.aop.prune system property can be set to turn off pruning.

                     java -Djboss.aop.prune=false ...
                  
-client/-server

Strangely enough, it seems that the -client VM switch is a little faster for JBoss AOP loadtime weaving that -server. If you are using the -server VM, trying switching to -client (the default).

Ignore

A way to completely ignore classes from being instrumented. This overrides whatever you have set up using the include/exclude filters. The system property is jboss.aop.ignore, and you can use wildcards in the classnames. As for include/exclude you may specify a comma separated list of class name patterns. This following example avoids instrumenting the cglib generated proxies for hibernate:

                        java -Djboss.aop.ignore=*$$EnhancerByCGLIB$$*
                  	

10.2.3. HotSwap

The HotSwap feature allows bytecode of your classes to be weaved in runtime. This results in application flow control changes to your classes only when joinpoints become intercepted (to do this, use the dynamic aop funcionality provided by JBoss AOP). This is a mode to be considered when you want to assure the flow control of your classes will be kept intact until a binding or a interceptor is added.

This mode is currently provided through the java.lang.instrument.Instrumentation hot swap functionality, which is part of the JVMTI (Java Virtual Machine Tool Interface). So, you cannot run JBoss AOP in this mode when using a previous JDK version.

To enable HotSwap, you have to add an argument to the Java command line in a very similar way to the Loadtime mode: -javaagent:jboss-aop.jar=-hotSwap. The difference is that the -hotSwap argument was added to the agent parameter list.

This way, if your jboss-aop.xml file is contained in a jar file, run:

$ java -cp=<classpath as described above> -Djboss.aop.path=<path to jboss-aop.xml> \
		-javaagent:jboss-aop.jar=-hotSwap com.blah.MyMainClass
            

And if your jboss-aop.xml file is contained in a jar, run the following command line:

$ java -cp=<classpath as described above> -javaagent:jboss-aop.jar=-hotSwap \
		com.blah.MyMainClass
            

The run-loadHotSwap batch/script files contained in the /bin folder of the distribution are similar to the run-load ones, described in the previous subsection. All aop libs are included in these script files. To use them, run:

$ run-load classpath [-aoppath path_to_aop.xml] [-aopclasspath path_to_annotated] \
		com.blah.MyMainClass [args...]
            

When hotswap is enabled, the prunning of classes is turned off. Therefore, if you try to configure the jboss.aop.prune option as true, this setup will be ignored.

As with the Loadtime mode, the HotSwap mode results in a boot time delay. Besides this drawback, the execution of some dynamic aop operations may be slower than in the other modes, when classes need to be hot swapped. The available options to tune performance are the same as described in the "Improving Loadtime Performance" subsection, except the pruning of classes.

10.2.4. User-Defined ClassLoaders

In order to be compatible with JBoss AOP, the ClassLoader responsible for loading your application's classes must be able to find class files as resources. This means that, given the name of a class that is in the classpath of your application, the methods below must all return the URL(s) of the corresponding class file(s):

public URL getResource(String name)
public Enumeration<URL> getResources(String name) throws IOException
public Enumeration<URL> getResourceAsStream(String name) throws IOException
            

Usually, there is no need to be concerned about this, as the ClassLoader implementations of Sun's JVM and JRockit follow the requirement above. On the other hand, if the application is being run with a user-defined ClassLoader, it is necessary to make sure the ClassLoader follows this important requirement.

10.3. JBoss Application Server

JBoss AOP is integrated with JBoss 4.0.1+ application server. The integration steps are different depending on what version of JBoss AS you are using and what JDK version you are using. It is also dependent on whether you want to use loadtime or compiletime instrumentation. JBoss 4.x comes with previous versions of JBoss AOP, which can be upgraded to AOP 2.0.x by using the ant scripts as explained in Section 8.2, “Installing with JBoss 4.0.x and JBoss 4.2.x Application Server for JDK 5”. JBoss 5 comes with AOP 2.0.x built in.

Based on what JDK you are on and what loadtime weaving option you want to you, you must configure JBoss AS differently.

10.3.1. Packaging AOP Applications

To deploy an AOP application in JBoss you need to package it. AOP is packaged similarly to SARs(MBeans). You can either deploy an XML file directly in the deploy/ directory with the signature *-aop.xml along with your package (this is how the base-aop.xml, included in the jboss-aop.deployer file works) or you can include it in the jar file containing your classes. If you include your xml file in your jar, it must have the file extension .aop and a jboss-aop.xml file must be contained in a META-INF directory, i.e. META-INF/jboss-aop.xml.

Note that in JBoss 5, you MUST specify the schema used, otherwise your information will not be parsed correctly. You do this by adding the xmlns="urn:jboss:aop-beans:1:0 attribute to the root aop element, as shown here:

<aop xmlns="urn:jboss:aop-beans:1.0">


</aop>
            
            

If you want to create anything more than a non-trivial example, using the .aop jar files, you can make any top-level deployment contain a .aop file containing the xml binding configuration. That is you can have a .aop file in an .ear file, or a .aop file in a war file etc. The bindings specified in the META-INF/jboss-aop.xml file contained in the .aop file will affect all the classes in the whole war!

To pick up a .aop file in an .ear file, it must be listed in the .ear/META-INF/application.xml as a java module, e.g.:


<?xml version='1.0'  encoding='UTF-8'?>
<!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN'
                             'http://java.sun.com/j2ee/dtds/application_1_2.dtd'>

<application>
    <display-name>AOP in JBoss example</display-name>
    <module>
        <java>example.aop</java>
    </module>
    <module>
        <ejb>aopexampleejb.jar</ejb>
    </module>
    <module>
        <web>
           <web-uri>aopexample.war</web-uri>
          <context-root>/aopexample</context-root>
       </web>
   </module>
</application>

			

Note that in newer versions of JBoss (>= 4.0.5), the contents of the .ear file are deployed in the order they are listed in the application.xml. When using loadtime weaving the bindings listed in the example.aop file must be deployed before the classes being advised are deployed, so that the bindings exist in the system before the ejb, servlet etc. classes are loaded. This is acheived by listing the .aop file at the start of the application.xml. Older versions of JBoss did not have this issue since the contained .aop files were deployed before anything else, and this still holds true for other types of archives such as .sar and .war files.

10.3.2. The JBoss AspectManager Service

The AspectManager Service is installed in both JBoss 5 and JBoss 4.x. It can be managed at run time using the JMX console which is found at http://localhost:8080/jmx-console. It is registered under the ObjectName jboss.aop:service=AspectManager. If you want to configure it on startup you need to edit some configuration files, which are different on JBoss 5 and JBoss 4.x, although the concepts are the same.

10.3.2.1. JBoss 5 AspectManager Service

In JBoss 5 the AspectManager Service is configured using a JBoss Microcontainer bean. The configuration file is jboss-5.x.x.GA/server/xxx/conf/aop.xml. The AspectManager Service is deployed with the following xml:


   <bean name="AspectManager" class="org.jboss.aop.deployers.AspectManagerJDK5">
      ...
      
      <property name="jbossIntegration"><inject bean="AOPJBossIntegration"/></property>

      <property name="enableLoadtimeWeaving">false</property>
      <!-- only relevant when EnableLoadtimeWeaving is true.
           When transformer is on, every loaded class gets
           transformed.  If AOP can't find the class, then it
           throws an exception.  Sometimes, classes may not have
           all the classes they reference.  So, the Suppressing
           is needed.  (i.e. Jboss cache in the default configuration -->
      <property name="suppressTransformationErrors">true</property>
      <property name="prune">true</property>
      <property name="include">org.jboss.test., org.jboss.injbossaop.</property>
      <property name="exclude">org.jboss.</property>
      <!-- This avoids instrumentation of hibernate cglib enhanced proxies
      <property name="ignore">*$$EnhancerByCGLIB$$*</property> -->
      <property name="optimized">true</property>
      <property name="verbose">false</property>
      <!--
         Available choices for this attribute are:
            org.jboss.aop.instrument.ClassicInstrumentor (default)
            org.jboss.aop.instrument.GeneratedAdvisorInstrumentor
       <property name="instrumentor">org.jboss.aop.instrument.ClassicInstrumentor</property>
      -->
          <!-- 
                By default the deployment of the aspects contained in 
                ../deployers/jboss-aop-jboss5.deployer/base-aspects.xml
                are not deployed. To turn on deployment uncomment this property
          <property name="useBaseXml">true</property>
          -->
   </bean>

               
            

In later sections we will talk about changing the class of the AspectManager Service, to do this replace the contents of the class attribute of the bean element.

10.3.2.2. JBoss 4.x AspectManager Service

In JBoss 4.x the AspectManager Service is configured using a JBoss Microcontainer bean. The configuration file is jboss-4.x.x.GA/server/default/deploy/jboss-aop-jdk50.deployer/META-INF/jboss-service.xml. The AspectManager Service is deployed with the following xml:


   <mbean code="org.jboss.aop.deployment.AspectManagerServiceJDK5"
      name="jboss.aop:service=AspectManager">
      <attribute name="EnableLoadtimeWeaving">false</attribute>
      <!-- only relevant when EnableLoadtimeWeaving is true.  
           When transformer is on, every loaded class gets 
           transformed.  If AOP can't find the class, then it 
           throws an exception.  Sometimes, classes may not have 
           all the classes they reference.  So, the Suppressing 
           is needed.  (i.e. Jboss cache in the default configuration -->
      <attribute name="SuppressTransformationErrors">true</attribute>
      <attribute name="Prune">true</attribute>
      <attribute name="Include">org.jboss.test, org.jboss.injbossaop</attribute>
      <attribute name="Exclude">org.jboss.</attribute>
      <!-- This avoids instrumentation of hibernate cglib enhanced proxies
      <attribute name="Ignore">*$$EnhancerByCGLIB$$*</attribute> -->
      <attribute name="Optimized">true</attribute>
      <attribute name="Verbose">false</attribute>
      <depends optional-attribute-name="JBossIntegrationWrapper" proxy-type="attribute">jboss.aop:service=JBoss4IntegrationWrapper</depends>
      <!-- 
         Available choices for this attribute are:
            org.jboss.aop.instrument.ClassicInstrumentor (default)
            org.jboss.aop.instrument.GeneratedAdvisorInstrumentor
       <attribute name="Instrumentor">org.jboss.aop.instrument.ClassicInstrumentor</attribute>
      -->
   </mbean>

               
            

In later sections we will talk about changing the class of the AspectManager Service, to do this replace the contents of the code attribute of the mbean element.

10.3.3. Loadtime transformation in JBoss AS Using Sun JDK

JBoss AS has special integration with JDK (from version 5.0 on) to do loadtime transformations. This section explains how to use it.

If you want to do load-time transformations with JBoss 5 and Sun JDK, these are the steps you must take.

  • Set the enableLoadtimeWeaving attribute/property to true. By default, JBoss application server will not do load-time bytecode manipulation of AOP files unless this is set. If suppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because sometimes a JBoss deployment will not have all the classes a class references.
  • Copy the pluggable-instrumentor.jar from the lib/ directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation.
  • Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS environment variable:
    set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME% -javaagent:pluggable-instrumentor.jar
    		            

Note that the class of the AspectManager Service must be org.jboss.aop.deployers.AspectManagerJDK5 on JBoss 5, or org.jboss.aop.deployment.AspectManagerServiceJDK5 as these are what work with the -javaagent weaver.

10.3.4. JBoss 5 and JRockit

JRockit also supports the -javaagent switch mentioned in Section 10.3.3, “Loadtime transformation in JBoss AS Using Sun JDK”. If you wish to use that, then the steps in Section 10.3.3, “Loadtime transformation in JBoss AS Using Sun JDK” are sufficient. However, JRockit also comes with its own framework for intercepting when classes are loaded, which might be faster than the -javaagent switch. If you wish to use this, there are three steps you must take.

If you want to do load-time transformations with JBoss 5 and JRockit using the special JRockit hooks, these are the steps you must take.

  • Set the enableLoadtimeWeaving attribute/property to true. By default, JBoss application server will not do load-time bytecode manipulation of AOP files unless this is set. If suppressTransformationErrors is true failed bytecode transformation will only give an error warning. This flag is needed because sometimes a JBoss deployment will not have all the classes a class references.
  • Copy the jrockit-pluggable-instrumentor.jar from the lib/ directory of your JBoss AOP distribution to the bin/ directory of your JBoss AOP application server installation.
  • Next edit run.sh or run.bat (depending on what OS you're on) and add the following to the JAVA_OPTS and JBOSS_CLASSPATH environment variables:
    # Setup JBoss sepecific properties
    JAVA_OPTS="$JAVA_OPTS -Dprogram.name=$PROGNAME \
       -Xmanagement:class=org.jboss.aop.hook.JRockitPluggableClassPreProcessor"
    JBOSS_CLASSPATH="$JBOSS_CLASSPATH:jrockit-pluggable-instrumentor.jar"
                      
  • Set the class of the AspectManager Service to be org.jboss.aop.deployers.AspectManagerJRockit on JBoss 5, or org.jboss.aop.deployment.AspectManagerService as these are what work with special hooks in JRockit.

10.3.5. Improving Loadtime Performance in a JBoss AS Environment

The same rules apply to JBoss AS for tuning loadtime weaving performance as standalone Java. See the previous chapter on tips and hints. YOU CANNOT USE THE SAME SYSTEM PROPERTIES THOUGH! Switches like pruning, optimized, and include/exclude are configured through the jboss-aop.deployer/META-INF/jboss-service.xml file talked about earlier in this chapter. You should be able to figure out how to turn the switches on/off from the above documentation.

10.4. Scoping aop to the classloader

By default all deployments in JBoss are global to the whole application server. That means that any ear, sar, jar etc. that is put in the deploy directory can see the classes from any other deployed archive. Similarly, aop bindings are global to the whole virtual machine. This "global" visibility can be turned off per top-level deployment.

10.4.1. Deploying as part of a scoped classloader

How the following works may be changed in future versions of jboss-aop. If you deploy a .aop file as part of a scoped archive, the bindings etc. applied within the .aop/META-INF/jboss-aop.xml file will only apply to the classes within the scoped archive and not to anything else in the application server. Another alternative is to deploy -aop.xml files as part of a service archive (SAR). Again if the SAR is scoped, the bindings contained in the -aop.xml files will only apply to the contents of the SAR file. It is not currently possible to deploy a standalone -aop.xml file and have that attach to a scoped deployment. Standalone -aop.xml files will apply to classes in the whole application server.

10.4.2. Attaching to a scoped deployment

If you have an application using classloader isolation, as long as you have "prepared your classes" you can later attach a .aop file to that deployment. If we have a .ear file scoped using a jboss-app.xml file, with the scoped loader repository jboss.test:service=scoped:

<jboss-app>
  <loader-repository>
      jboss.test:service=scoped
  </loader-repository>
</jboss-app>

We can later deploy a .aop file containing aspects and configuration to attach that deployment to the scoped .ear. This is done using the loader-repository tag in the .aop files META-INF/jboss-aop.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<aop>
   <loader-repository>jboss.test:service=scoped</loader-repository>

   <!-- Aspects and bindings -->
</aop>

This has the same effect as deploying the .aop file as part of the .ear as we saw previously, but allows you to hot deploy aspects into your scoped application.