免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 975 | 回复: 0
打印 上一主题 下一主题

AOP4 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-19 16:22 |只看该作者 |倒序浏览
6.4. Choosing which AOP declaration style to use
    Once you have decided that an aspect is the best approach for implementing a
    given requirement, how do you decide between using Spring AOP or AspectJ,
    and between the Aspect language (code) style, @AspectJ annotation style, and
        the XML style? These decisions are influenced by a number of factors including
        application requirements, development tools, and team familiarity with AOP.
   
6.4.1. Spring AOP or full AspectJ?
Use the simplest thing that can work. Spring AOP is simpler than using
            full AspectJ as there is no requirement to introduce the AspectJ
            compiler / weaver into your development and build processes.
            If you only need to advise the execution of operations on Spring beans,
            then Spring AOP is the right choice. If you need to advise domain objects,
            or any other object not managed by the Spring container, then you will
            need to use AspectJ. You will also need to use AspectJ if you wish to
            advise join points other than simple method executions (for example, call
            join points, field get or set join points, and so on).
When using AspectJ, you have the choice of the AspectJ language syntax
            (also known as the "code style") or the @AspectJ annotation style.
            If aspects play a large role in your design, and you are able to use the
           
AspectJ Development Tools (AJDT)
                in Eclipse, then the AspectJ language syntax is the preferred option: it is cleaner
                and simpler because the language was purposefully designed for writing aspects.
                If you are not using Eclipse, or have only a few aspects that do not play a
                major role in your application, then you may want to consider using the @AspectJ
                style and sticking with a regular Java compilation in your IDE, and adding an aspect
            weaving (linking) phase to your build scripts.
6.4.2. @AspectJ or XML for Spring AOP?
                        The XML style will be most familiar to existing Spring users. It can be
                        used with any JDK level (referring to named pointcuts from within
                        pointcut expressions does still require Java 5 though) and is backed
                        by genuine POJOs. When using AOP as a tool to configure enterprise
                        services (a good test is whether you consider the pointcut expression
                        to be a part of your configuration you might want to change independently)
                        then XML can be a good choice. With the XML style it is arguably
                        clearer from your configuration what aspects are present in the system.
           
                        The XML style has two disadvantages. Firstly it does not fully encapsulate
                        the implementation of the requirement it addresses in a single place.
                        The DRY principle says that there should be a single, unambiguous, authoritative
                        representation of any piece of knowledge within a system. When using the
                        XML style, the knowledge of how a requirement is implemented is split across
                        the declaration of the backing bean class, and the XML in the configuration
                        file. When using the @AspectJ style there is a single module - the aspect - in
                        which this information is encapsulated. Secondly, the XML style is more
                        limited in what in can express than the @AspectJ style: only the "singleton"
                        aspect instantiation model is supported, and it is not possible to combine
                        named pointcuts declared in XML. For example, in the @AspectJ style we
                        can write something like:
           
  @Pointcut(execution(* get*()))
  public void propertyAccess() {}
  @Pointcut(execution(org.xyz.Account+ *(..))
  public void operationReturningAnAccount() {}
  @Pointcut(propertyAccess() && operationReturningAnAccount())
  public void accountPropertyAccess() {}
In the XML style I certainly can declare the first two pointcuts:
  
  
                The downside of the XML approach becomes evident in this case because I
                cannot define the 'accountPropertyAccess' pointcut by
                combining these definitions.
       
                The @AspectJ style supports additional instantiation models, and richer
                pointcut composition. It has the advantage of keeping the aspect as a
                modular unit. It also has the advantage the @AspectJ aspects can be
                understood both by Spring AOP and by AspectJ - so if you later decide
                you need the capabilities of AspectJ to implement additional requirements
                then it is very easy to migrate to an AspectJ based approach.
       
So much for the pros and cons of each style then: which is best? If you are not using Java5
        (or above) then clearly the XML-style is the best because it is the only option available to you.
        If you are using Java5+, then you really will have to come to your own decision as to which style suits
        you best. In the experience of the Spring team, we advocate the use of the @AspectJ style whenever
        there are aspects that do more than simple "configuration" of enterprise services. If you are writing,
        have written, or have access to an aspect that is not part of the business contract of a particular
        class (such as a tracing aspect), then the XML-style is better.
6.5. Mixing aspect types
It is perfectly possible to mix @AspectJ style aspects using the autoproxying
    support, schema-defined  aspects,
     declared advisors and even proxies and
    interceptors defined using the Spring 1.2 style in the same configuration. All of
    these are implemented using the same underlying support mechanism and will co-exist
    without any difficulty.
6.6. Proxying mechanisms
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given
    target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface then a JDK
    dynamic proxy will be used. All of the interfaces implemented by the target type will be
    proxied. If the target object does not implement any interfaces then a CGLIB proxy
    will be created.
If you want to force the use of CGLIB proxying (for example, to proxy every
    method defined for the target object, not just those implemented by its interfaces)
    you can do so. However, there are some issues to consider:

  • final methods cannot be advised, as they cannot
            be overriden.

  • You will need the CGLIB 2 binaries on your classpath, whereas
            dynamic proxies are available with the JDK. Spring will automatically
            warn you when it needs CGLIB but it isn't available on the classpath.
            

  • The
    constructor of your proxied object will be called twice. This is a
    natural consequence of the CGLIB proxy model whereby a subclass is
    generated for each proxied object. For each proxied instance, two
    objects are created: the actual proxied object and an instance of the
    subclass that implements the advice. This behavior does not show when
    using JDK proxies. Usually, calling the constructor of the proxied type
    twice, is not a huge problem, as there are usually only assignments
    taking place and no real logic is (and probably should be) implemented
    in the constructor.

                    To force the use of CGLIB proxies set the value of the proxy-target-class
                    attribute of the  element to true:
           
    proxy-target-class="true">
           
           
           
    To force CGLIB proxying when using the @AspectJ autoproxy support, set the
               'proxy-target-class' attribute of the
               true:
               element to
    proxy-target-class="true"/>6.6.1. Understanding AOP proxies
    Spring AOP is proxy-based. It is vitally important that you grasp
        the semantics of what that last statement actually means before you write your own aspects or
        use any of the Spring AOP-based aspects supplied with the Spring Framework.
    Consider first the scenario where you have a plain-vanilla, un-proxied,
        nothing-special-about-it, straight object reference, as illustrated by the following code snippet.
    public class SimplePojo implements Pojo {
       public void foo() {
          // this is a direct method call on the 'this' reference
          this.bar();
       }
       
       public void bar() {
          // some logic...
       }
    }
    If you invoke a method on an object reference, the method is invoked
            directly on that object reference, as can be seen below.
                   

           
    public class Main {
       public static void main(String[] args) {
       
          Pojo pojo = new SimplePojo();
          
          // this is a direct method call on the 'pojo' reference
          pojo.foo();
       }
    }
    Things change slightly when the reference that client code has is a proxy. Consider the
            following diagram and code snippet.
                   

           
    public class Main {
       public static void main(String[] args) {
       
          ProxyFactory factory = new ProxyFactory(new SimplePojo());
          factory.addInterface(Pojo.class);
          factory.addAdvice(new RetryAdvice());
          Pojo pojo = (Pojo) factory.getProxy();
          
          // this is a method call on the proxy!
          pojo.foo();
       }
    }
    The key thing to understand here is that the client code inside the
            main(..) of the Main class
            has a reference to the proxy. This means that method calls on that object
            reference will be calls on the proxy, and as such the proxy will be able to delegate to
            all of the interceptors (advice) that are relevant to that particular method call.
            However, once the call has finally reached the target object, the SimplePojothis.bar() or this.foo(), are going to be
            invoked against the thisnot
            the proxy. This has important implications. It means that self-invocation is not
            going to result in the advice associated with a method invocation getting a chance to execute.
            reference in this case, any method calls that it may make on itself, such as
             reference, and
    Okay, so what is to be done about this? The best approach (the term best is used loosely here)
            is to refactor your code such that the self-invocation does not happen. For sure, this does entail
            some work on your part, but it is the best, least-invasive approach. The next approach is
            absolutely horrendous, and I am almost reticent to point it out precisely because it is so
            horrendous. You can (choke!) totally tie the logic within your class to Spring AOP by doing
            this:
    public class SimplePojo implements Pojo {
       public void foo() {
          // this works, but... gah!
          ((Pojo) AopContext.currentProxy()).bar();
       }
       
       public void bar() {
          // some logic...
       }
    }
    This totally couples your code to Spring AOP, and it makes the class
        itself aware of the fact that it is being used in an AOP context, which flies in the face of AOP.
        It also requires some additional configuration when the proxy is being created:
    public class Main {
       public static void main(String[] args) {
       
          ProxyFactory factory = new ProxyFactory(new SimplePojo());
          factory.adddInterface(Pojo.class);
          factory.addAdvice(new RetryAdvice());
          factory.setExposeProxy(true);
          Pojo pojo = (Pojo) factory.getProxy();
          // this is a method call on the proxy!
          pojo.foo();
       }
    }
    Finally, it must be noted that AspectJ does not have this self-invocation issue because it is
            not a proxy-based AOP framework.
    6.7. Programmatic creation of @AspectJ Proxies
    In addition to declaring aspects in your configuration using either
             or ,
            it is also possible programmatically to create proxies that advise target objects. For the
            full details of Spring's AOP API, see the next chapter. Here we want to focus on the ability
            to automatically create proxies        using @AspectJ aspects.
    The class org.springframework.aop.aspectj.annotation.AspectJProxyFactory
            can be used to create a proxy for a target object that is advised by one or more
            @AspectJ aspects. Basic usage for this class is very simple, as illustrated below. See
            the Javadocs for full information.
    // create a factory that can generate a proxy for the given target object
    AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
    // add an aspect, the class must be an @AspectJ aspect
    // you can call this as many times as you need with different aspects
    factory.addAspect(SecurityManager.class);
    // you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
    factory.addAspect(usageTracker);       
    // now get the proxy object...
    MyInterfaceType proxy = factory.getProxy();6.8. Using AspectJ with Spring applications
              Everything we've covered so far in this chapter is pure Spring AOP. In this section,
              we're going to look at how you can use the AspectJ compiler/weaver instead of or in
              addition to Spring AOP if your needs go beyond the facilities offered by Spring AOP
              alone.
             
              Spring ships with a small AspectJ aspect library (it's available standalone in
              your distribution as spring-aspects.jar, you'll need to add
        this to your classpath to use the aspects in it).
    Section 6.8.1, “Using AspectJ to dependency inject domain objects with Spring”
              and
    Section 6.8.2, “Other Spring aspects for AspectJ”
    discuss the content of this library and how you
              can use it.
    Section 6.8.3, “Configuring AspectJ aspects using Spring IoC”
    discusses how to dependency inject AspectJ
              aspects that are woven using the AspectJ compiler. Finally,
             
    Section 6.8.4, “Using AspectJ Load-time weaving (LTW) with Spring applications”
    provides an introduction to load-time weaving for Spring applications
              using AspectJ.
    6.8.1. Using AspectJ to dependency inject domain objects with Spring
                      The Spring container instantiates and configures beans defined in your
                      application context. It is also possible to ask a bean factory to configure
                      a pre-existing object given the name of a bean definition
                      containing the configuration to be applied. The spring-aspects.jaroutside of the control of any container. Domain objects
                      often fall into this category: they may be created programmatically using the
                      new operator, or by an ORM tool as a result of a database query.
                   
                      contains an annotation-driven aspect that exploits this capability to allow dependency-injection
                      of any object. The support is intended to be used for objects created
                      
                      The @Configurable annotation marks a class as eligible for
                      Spring-driven configuration. In the simplest case it can be used just as a
                      marker annotation:
                   
    package com.xyz.myapp.domain;
    import org.springframework.beans.factory.annotation.Configurable;
    @Configurable
    public class Account {
       ...
    }
                            When used as a marker interface in this way, Spring will configure
                            new instances of the annotated type (Account in this case) using a
                            prototypical bean definition with the same name as the fully-qualified
                            type name (com.xyz.myapp.domain.Account). Since the
                            default name for a bean is the fully-qualified name of its type, a
                            convenient way to declare the prototype definition is simply to omit the
                            id attribute:
      
      ...
    If you want to explicitly specify the name of the prototype bean
                    definition to use, you can do so directly in the annotation:
    package com.xyz.myapp.domain;
    import org.springframework.beans.factory.annotation.Configurable;
    @Configurable("account")
    public class Account {
       ...
    }
    Spring will now look for a bean definition named "account" and
                    use that as a prototypical definition to configure new Account
                    instances.
    You can also use autowiring to avoid having to specify a prototypical
                    bean definition at all. To have Spring apply autowiring use the
                    autowire property of the @Configurable annotation: specify either
                    @Configurable(autowire=Autowire.BY_TYPE) or
                    @Configurable(autowire=Autowire.BY_NAME for autowiring
                    by type or by name respectively.
    Finally you can enable Spring dependency checking for the object references
                    in the newly created and configured object by using the dependencyCheck
                    attribute (for example:
                            @Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true) ).
                    If this attribute is set to true, then Spring will validate after configuration that all properties
                    (that are not primitives or collections) have been set.
                   
    Using the annotation on its own does nothing of course. It's the
                    AnnotationBeanConfigurerAspect in spring-aspects.jar that
                    acts on the presence of the annotation. In essence the aspect says "after
                    returning from the initialization of a new object of a type with the
                    @Configurable annotation, configure the newly created object using Spring
                    in accordance with the properties of the annotation". For this to work the
                    annotated types must be woven with the AspectJ weaver - you can either
                    use a build-time ant or maven task to do this (see for example the
                    AspectJ
                    Development Environment Guide) or load-time weaving (see
    Section 6.8.4, “Using AspectJ Load-time weaving (LTW) with Spring applications”
    ).
                   
    The AnnotationBeanConfigurerAspect itself needs
                    configuring by Spring (in order to obtain a reference to the bean factory that
                    is to be used to configure new objects). The Spring AOP namespace defines a
                    convenient tag for doing this. Simply include the following in your
                    application context configuration:
    If you are using the DTD instead of schema, the equivalent definition is:
    Instances of @Configurable objects created before
                    the aspect has been configured will result in a warning being issued to the
                    log and no configuration of the object taking place. An example might be
                    a bean in the Spring configuration that creates domain objects when it is
                    initialized by Spring. In this case you can use the "depends-on" bean
                    attribute to manually specify that the bean depends on the
                    configuration aspect.
      ...
    6.8.1.1. Unit testing @Configurable objects
    One of the goals of the @Configurable support is to enable independent
                      unit testing of domain objects without the difficulties associated with
                      hard-coded lookups. If @Configurable types have not been woven by AspectJ
                      then the annotation has no affect during unit testing, and you can simply
                      set mock or stub property references in the object under test and proceed
                      as normal. If @Configurable types have been woven by
                      AspectJ then you can still unit test outside of the container as normal,
                      but you will see a warning message each time that you construct an
                      @Configurable object indicating that it has not been configured by Spring.
    6.8.1.2. Working with multiple application contexts
    The AnnotationBeanConfigurerAspect used to implement
                      the @Configurable support is an AspectJ singleton aspect. The scope of a
                      singleton aspect is the same as the scope of static members, that is to say there is
                      one aspect instance per classloader that defines the type. This means that if
                      you define multiple application contexts within the same classloader hierarchy
                      you need to consider where to define the  bean and where to place
                      spring-aspects.jaron the classpath.
                              Consider a typical Spring web-app configuration with a shared parent application
                              context defining common business services and everything needed to support
                              them, and one child application context per servlet containing definitions
                              particular to that servlet. All of these contexts will co-exist within the
                              same classloader hierarchy, and so the AnnotationBeanConfigurerAspect
                              can only hold a reference to one of them. In this case we recommend
                              defining the  bean in the
                              shared (parent) application context: this defines the services that you are
                              likely to want to inject into domain objects. A consequence is that you cannot
                              configure domain objects with references to beans defined in the child
                              (servlet-specific) contexts using the @Configurable mechanism
                              (probably not something you want to do anyway!).
                      
                              When deploying multiple web-apps within the same container, ensure that each
                              web-application loads the types in spring-aspects.jar using its own classloader
                              (for example, by placing spring-aspects.jar
                              in 'WEB-INF/lib'). If spring-aspects.jar
                              is only added to the container wide classpath (and hence loaded by the shared
                              parent classloader), all web applications will share the same aspect instance
                              which is probably not what you want.  
                      
    6.8.2. Other Spring aspects for AspectJ
    In addition to the @Configurable support,
                    spring-aspects.jar contains an
                    AspectJ aspect that can be used to drive Spring's transaction management for
                    types and methods annotated with the @Transactional annotation.
                    This is primarily intended for users who want to use Spring's transaction support outside of the Spring container.
    The aspect that interprets @Transactional annotations is the
                    AnnotationTransactionAspect. When using this
                    aspect, you must annotate the implementation class
                (and/or methods within that class), notnot inherited. the interface
                (if any) that the class implements. AspectJ follows Java's rule that annotations on
                interfaces are
    A @Transactional annotation on a class specifies the default transaction
            semantics for the execution of any public operation in the class.
    A @Transactional annotation on a method within the class overrides the
            default transaction semantics given by the class annotation (if present).
            Methods with public, protected, and default visibility may all be annotated.
            Annotating protected and default visibility methods directly is the only way
            to get transaction demarcation for the execution of such operations.
    For AspectJ programmers that want to use the Spring configuration and
                    transaction management support but don't want to (or can't) use annotations,
                    spring-aspects.jar also contains abstract aspects you can extend to provide
                    your own pointcut definitions. See the Javadocs for
                    AbstractBeanConfigurerAspect and
                    AbstractTransactionAspect for more information. As an example,
                    the following excerpt shows how you could write an aspect to configure
                    all instances of objects defined in the domain model
                    using prototypical bean definitions that match the fully-qualified class
                    names:
    public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect {
      public DomainObjectConfiguration() {
        setBeanWiringInfoResolver(new ClassNameBeanWiringInfoResolver());
      }
      // the creation of a new bean (any object in the domain model)
      protected pointcut beanCreation(Object beanInstance) :
        initialization(new(..)) &&
        SystemArchitecture.inDomainModel() &&
        this(beanInstance);
                                         
    }6.8.3. Configuring AspectJ aspects using Spring IoC
    When using AspectJ aspects with Spring applications, it's natural to want
                    to configure such aspects using Spring. The AspectJ runtime itself is responsible
                    for aspect creation, and the means of configuring the AspectJ created aspects via
                    Spring depends on the AspectJ instantiation model (per-clause) used by the aspect.
                   
    The majority of AspectJ aspects are
                    singleton aspects. Configuration of these aspects is very
                    easy, simply create a bean definition referencing the aspect type as normal, and
                    include the bean attribute 'factory-method="aspectOf"'. This
                    ensures that Spring obtains the aspect instance by asking AspectJ for it rather
                    than trying to create an instance itself. For example:
      
    For non-singleton aspects, the easiest way to configure them is to create
               prototypical bean definitions and annotate use the @Configurable support from
               spring-aspects.jar to configure the aspect instances once they have bean created
               by the AspectJ runtime.
    If you have some @AspectJ aspects that you want to weave with AspectJ
               (for example, using load-time weaving for domain model types) and other @AspectJ
               aspects that you want to use with Spring AOP, and these aspects are all configured
               using Spring, then you'll need to tell the Spring AOP @AspectJ autoproxying support
               which subset of the @AspectJ aspects defined in the configuration should be used
               for autoproxying. You can do this by using one or more
               elements inside the  declaration.
               Each include element specifies a name pattern, and only beans with names matched
               by at least one of the patterns will be used for Spring AOP autoproxy configuration:
      
      
    6.8.4. Using AspectJ Load-time weaving (LTW) with Spring applications
    Load-time weaving (or LTW) refers to the process of weaving AspectJ aspects
                    with an application's class files as they are loaded into the VM. For full details
                    on configuring load-time weaving with AspectJ, see the
                   
                    LTW section of the AspectJ Development Environment Guide
                    . We will focus here on the essentials of configuring load-time weaving
                    for Spring applications running on Java 5.
                    Load-time weaving is controlled by defining a file 'aop.xml' in
                    the META-INF directory. AspectJ automatically looks for all 'META-INF/aop.xml' files
                    visible on the classpath and configures itself based on the aggregation of their
                    content.
                   
                    A basic META-INF/aop.xml for your application should look like this:
                   
       
       
       
             
       
                            The  element tells AspectJ which set of types
                            should be included in the weaving process. Use the package prefix for your
                            application followed by "..*" (meaning '... and any type defined in a subpackage
                            of this') as a good default. Using the include element is important as otherwise
                            AspectJ will look at every type loaded in support of your application (including
                            all the Spring library classes and many more besides). Normally you don't want
                            to weave these types and don't want to pay the overhead of AspectJ attempting
                            to match against them.
                   
                            To get informational messages in your log file regarding the activity of the
                            load-time weaver, add the following options to the weaver element:
                   
       
       
       
             
       
    Finally, to control exactly which aspects are used, you can use the
            aspects element. By default all defined aspects are used for
            weaving (spring-aspects.jar contains a META-INF/aop.xml file that defines the
            configuration and transaction aspects). If you were using spring-aspects.jar, but
            only want the configuration support and not the transaction support you could
            specify this as follows:
       
       
      
       
      
      
       
       
    On the Java 5 platform, load-time weaving is enabled by specifying the following
            VM argument when launching the Java virtual machine:
    -javaagent:/aspectjweaver.jar6.9. Further Resources
    More information on AspectJ can be found at the
              AspectJ home page.
    The book Eclipse AspectJ by Adrian Colyer et. al. (Addison-Wesley,
              2005) provides a comprehensive introduction and reference for the AspectJ language.
    The excellent AspectJ in Action by Ramnivas Laddad (Manning, 2003)
            comes highly recommended as an introduction to AOP; the focus of the book is on
            AspectJ, but a lot of general AOP themes are explored in some depth.
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/24141/showart_324462.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP