当前位置: 首页 > 工具软件 > JBoss AOP > 使用案例 >

JBoss AOP之XML绑定

屠嘉勋
2023-12-01

Resolving XML

    Jboss AOP在运行时分解Poincut和advice绑定。所以绑定是发布时间的事。

Standalone XML Resolving

    当在application server之外运行Jboss AOP时,通过下面的方式可以让Jboss AOP框架分解XML。
    1)jboss.aop.path:系统属性,windows是";"unix是":"。Jboss AOP将会加载在这些目录下的*-aop.xml文件。

    2)META-INF/jboss-aop.xml在classpath中任何Jar文件中在META-INF/下的jboss-aop.xml的都会被加载。Jboss AOP使用ClassLoader.getResoures("META-INF/jboss-aop.xml")来获取所有的文件。

aspect

    <aspect>标记为声明aspect类的AOP容器,当他们也用来配置aspect。

Basic Definition    

<aspect class="org.jboss.MyAspect"/>
    在基本的声明总,需要指定aspect类的全名。如果需要通过AspectManager来引用aspect,aspect的name与class name一致。aspect的默认scope为PER_VM。需要注意的是,aspect实例并不是发布时创建,而是按需创建。

Scope    

<aspect class="org.jboss.MyAspect" scope="PER_VM"/>

    scope属性定义了aspect实例在什么时候创建。

名字描述
PER_VM整个JVM中每个aspect类只分配一个实例
PER_CLASS为一个普通class仅分配一个aspect class实例。如果aspect的一个advice绑定到普通类上,此实例才被创建。
PER_INSTANCE为每个advice实例对象创建一个aspect实例。如果一个method有一个advice被匹配,advice的实例会被分配,此时会有一个aspect被创建。
PER_JOINPOINT为每个joinpoint advice创建一个aspect实例。如果joinpoint是静态成员,仅会有一个aspect实例被创建。
PER_CLASS_JOINPOINT为每个advice joinpoint创建一个aspect实例,次aspect实例被joinpioint类的每个实例共享。

Configuration

<aspect class="org.jboss.SomeAspect">
    <attribute name="SomeIntValue">55</attribute>
    <advisor-attribute name="MyAdvisor"/>
    <instance-advisor-attribute name="MyInstanceAdvisor"/>
    <joinpoint-attribute name="MyJoinpoint"/>
</aspect>
aspect默认使用JavaBean风格配置。<attribute>标签将委托给set方法,且转换类型。此外可以注入AOP运行时构造器给aspect,此处有类型属性。

<advisor-attribute> org.jboss.aop.Advisor
<instance-advisor-attribute> org.jboss.aop.InstanceAdvisor 
<joinpoint-attribute> org.jboss.aop.joinpoint.Joinpoint

Name

   如果没有定义name属性,aspect的name与class相同或factory属性值相同。
配置demo
<aspect class="org.jboss.SomeAspect">
    <attribute name="SomeIntValue">55</attribute>
    <advisor-attribute name="MyAdvisor"/>
    <instance-advisor-attribute name="MyInstanceAdvisor"/>
    <joinpoint-attribute name="MyJoinpoint"/>
</aspect>
public class SomeAspect {
    public SomeAspect() {}
    public void setSomeIntValue(int val) {...}
    public void setMyAdvisor(org.jboss.aop.Advisor advisor) {...}
    public void setMyInstanceAdvisor(org.jboss.aop.InstanceAdvisor advisor) {...}
    public void setMyJoinpoint(org.jboss.aop.joinpoint.Joinpoint joinpoin) {...}
}

Aspect Factories

<aspect name="MyAspect" factory="org.jboss.AspectConfigFactory" scope="PER_CLASS">
    <some-arbitrary-xml>value</some-arbitrary-xml>
</aspect>
    如果不喜欢默认的aspect的JavaBean配置,或者将aspect创建委托给其他容器,可以指定factory属性而不是class属性。在aspect XML声明中指定XML,它将会被传递给factory类。Factory必须实现org.jboss.aop.advice.AspectFactory。

interceptor

<interceptor class="org.jboss.MyInterceptor" scope="PER_VM"/>
<interceptor class="org.jboss.SomeInterceptor">
    <attribute name="SomeIntValue">55</attribute>
    <advisor-attribute name="MyAdvisor"/>
    <instance-advisor-attribute name="MyInstanceAdvisor"/>
    <joinpoint-attribute name="MyJoinpoint"/>
</interceptor>
<interceptor name="MyAspect" factory="org.jboss.InterceptorConfigFactory" scope="PER_CLASS">
    <some-arbitrary-xml>value</some-arbitrary-xml>
</interceptor>
    Interceptors的XML定义与aspect一致。

bind

<bind pointcut="execution(void Foo->bar())">
    <interceptor-ref name="org.jboss.MyInterceptor/>
    <before name="beforeAdvice" aspect="org.jboss.MyAspect"/>
    <around name="aroundAdvice" aspect="org.jboss.MyAspect"/>
    <after name="afterAdvice" aspect="org.jboss.MyAspect"/>
    <throwing name="throwingAdvice" aspect="org.jboss.MyAspect"/>
    <finally name="finallyAdvice" aspect="org.jboss.MyAspect"/>
    <advice name="trace" aspect="org.jboss.MyAspect"/>
</bind>

    bind:标签用来绑定advice,或interceptor到joinpoint。pointcut属性必选,至少一个advice或interceptor-ref被定义。

    interceptor-ref:它 必须引用已存在的interceptor定义。
    before,around,after,throwing和finally:所有这些都有tag属性,映射到aspect定义的名称。
    advice:与before等相似,但不必指定advice的类型。它会选择默认的advice类型around。

stack

    stacks允许定义一组advice和interceptor,便于在bind中引用。
<stack name="stuff">
    <interceptor class="SimpleInterceptor1" scope="PER_VM"/>
    <advice name="trace" aspect="org.jboss.TracingAspect"/>
    <interceptor class="SimpleInterceptor3">
    <attribute name="size">55</attribute>
</interceptor>
</stack>
<bind pointcut="execution(* POJO->*(..))">
    <stack-ref name="stuff"/>
</bind>

pointcut

    pointcut标签允许你定义pointcut表达式,便于在bind内引用。
<pointcut name="publicMethods" expr="execution(public * *->*(..))"/>
<pointcut name="staticMethods" expr="execution(static * *->*(..))"/>
<bind pointcut="publicMethods AND staticMethods">
    <interceptor-ref name="tracing"/>
</bind>

introduction

interface introductions

    introduction标签允许强制现存的类来实现一个特定接口。

<introduction class="org.acme.MyClass">
    <interfaces>java.io.Serializable</interfaces>
</introduction>

    上面的声明,org.acme.Myclass将会被强制实现java.io.Serializalbe接口。class属性可以是通配符,但不能是布尔表达式。如果需要更加复杂的类型表达式,可以使用expr属性替代。

<introduction expr="has(* *->@test(..)) OR class(org.acme.*)">
    <interfaces>java.io.Serializable</interfaces>
</introduction>
expr可以是在typedef表达式内允许的任何类型表达式

Mixins

    当引入接口时,也可以定义一个混合类,该类将提供接口的实现。
<introduction class="org.acme.MyClass">
    <mixin>
       <interfaces>java.io.Externalizable</interfaces>
       <class>org.acme.ExternalizableMixin</class>
       <construction>new org.acme.ExternalizableMixin(this)</construction>
    </mixin>
</introduction>
    interface:引入的接口清单
    class:混合类的类型
    construction:此construction statment允许你指定任何代码来创建这个混合类。这段代码直接嵌入在引入类中。

cflow-stack

    Control flow是运行时构造。它允许指定poincut参数来解析Java程序的调用栈。例如,method A从Constructor A内调用method B,调用methodC,调用method D,触发这个advice。
<cflow-stack name="recursive2">
    <called expr="void POJO->recursive(int)"/>
    <called expr="void POJO->recursive(int)"/>
    <not-called expr="void POJO->recursive(int)"/>
</cflow-stack>

cflow-statck有name,和多个called和not-called元素,它定义了使用Java call stack各自构造器或方法调用。expr属性必须是方法或构造器表达式。called,expr必须出现在call statck内。not-called,不允许在stack内有指定的表达式。上例中,如果栈内有两个且仅有两个recursive方法调用,会触发cflow-stack。可以在bind元素中通过cflow属性引用它。

<bind pointcut="execution(void POJO->recursive(int))"
    cflow="recursive2 AND !cflow2">
    <interceptor class="SimpleInterceptor"/>
</bind>

typedef

<typedef name="jmx" expr="class(@org.jboss.jmx.@MBean) OR \
    has(* *->org.jboss.jmx.@ManagedOperation) OR 
    has(* *->org.jboss.jmx.@ManagedAttribute)"/>
<pointcut name="stuff" expr="execution(* $typedef{jmx}->*(..))"/>
<introduction expr="class($typedef{jmx})">
typedef允许定义复杂类型的表达式,然后在pointcut中使用。

dynamic-cflow

    dynamic-cflow允许定义被执行的代码,它必须解释为true时才能触发。测试在运行是动态发生,且当和pointcut表达式绑定时允许你做运行时检查:是否advice并定应该被执行。
package org.jboss.aop.pointcut;
import org.jboss.aop.joinpoint.Invocation;
public interface DynamicCFlow
{
    boolean shouldExecute(Invocation invocation);
}

<dynamic-cflow name="simple" class="org.jboss.SimpleDynamicCFlow"/>
<bind expr="execution(void Foo->bar())" cflow="simple">

prepare

    prepare标签允许定义pointcut表达式,任何匹配此表达式的joinpoint会被且人,且字节码被instrument。这允许你热部署,且运行时绑定aspect。仅需要定义pointcut表达式,匹配想要instrument的joinpoint。
<prepare expr="execution(void Foo-bar())"/>


 类似资料: