Inter-type declarations in ASPECTJ (member injection)

Source: Internet
Author: User
Tags gety

In the first glimpse of AspectJ, we mentioned that ASPECTJ provides three new constructs for Java, pointcut,advice and Inter-type Declaration (ITD), And we've introduced a simple demo of how to use pointcut and advice. This article will introduce what Inter-type declaration is, what can be done, and finally, a demo will show how to use it. The following article will mainly use ITD to represent Inter-type declaration.

The demo code in this article can be found in GitHub Aspect-demo.

ITD and member injection

Inter-type Declaration (ITD), translated into Chinese is a type of inter-declaration. Even if I see Chinese translation, I believe we are still confused, unintelligible, so I am not very fond of some English names, especially the technical name of the blunt translation, which will only increase the understanding of the burden of everyone. In fact, a different argument may be better understood, Member introduction (member injection), and its purpose is to inject some new member variables or member methods into existing classes by aspect way. With aspect, we can inject the following members into a class:

    • Member variables (final or non-final)
    • Method
    • constructor function

In addition to adding content to a class, aspect can also modify the interface (interface) in Java to inject in existing interfaces:

    • Default implementation of the method
    • A non-final domain

The access modifiers for members injected through ITD can be:

    • Private member is the target class, but it is only visible to the aspect script, but not to the target class;
    • Public: Members declared as public are visible to all classes and apsect;
    • Default Package Protected: The packet visibility here is relative to the package that the aspect resides in, not the package that contains the target class.
Inter-type Declaration Example

Before you write aspect, prepare a simple Java class:

package cc.databus.aspect.intertype;public class Point {    private int x;    private int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    public int getY() {        return y;    }    public void setY(int y) {        this.y = y;    }}

With this basic class, let's look at how to modify the interface, member variables, and member methods implemented by this class through aspect. Here is our aspect code:

Package Cc.databus.aspect.intertype;public aspect Pointaspect {//Creates a new interface named Hasname private int    Erface hasname{}//Make class Ppint implements Hashname declare Parents:point implements Hasname;    Make Hasname have a field named name Private String Hasname.name;    Make Hasname have a method GetName () and default implemented public String Hasname.getname () {return name; }//Make Hasname have a method named SetName and default public void Hasname.setname (String name) {this.na    me = name;    }//Add a field named created to class Point//with default value 0 long point.created = 0;    Add a field named LastUpdated to class Point//with default value 0 Private long point.lastupdated = 0; Add a private method setupdated () private void point.setupdated () {this.lastupdated = System.currenttimemill    Is (); }//Implement ToString () for point//include the fields added in the aspectFile public String point.tostring () {return String.Format ("point: {name=%s, x=%d;    y=%d, created=%d, updated=%d} ", GetName (), GetX (), GetY (), created, lastupdated); }//Pointcut the constructor, and set the value for created after () returning (point P): Call (point.new (..)) &&        amp;!within (pointaspect) {System.out.println (Thisjoinpointstaticpart);        System.out.println ("Set created");    p.created = System.currenttimemillis ();    }//define a pointcut for SetX and sety pointcut Update (point P): Target (P) && call (void point.set* (..)); Make the lastupdated updated every time//SetX or sety invoked after (point P): Update (P) &&!within (p        Ointaspect) {System.out.println ("set updated for point due to" + Thisjoinpointstaticpart);    P.setupdated (); }}

In the aspect file above, we first define an interface and let the Point class implement the interface, and add a member variable (name) to the new interface and implement the corresponding Setter/getter:

    // creates a new interface named HasName    private interface HasName{}    // make class Ppint implements HashName    declare parents: Point implements HasName;    // make HasName has a field named name    private String HasName.name;    // make HasName has a method getName() and default implemented    public String HasName.getName() {        return name;    }    // make HasName has a method named setName and default    public void HasName.setName(String name) {        this.name = name;    }

We then added two member variables to the point class and implemented two member methods. where the ToString () interface is implemented, the member variables injected through aspect are also included in the result:

    // add a field named created to class Point    // with default value 0    long Point.created = 0;    // add a field named lastUpdated to class Point    // with default value 0    private long Point.lastUpdated = 0;    // add a private method setUpdated()    private void Point.updated() {        this.lastUpdated = System.currentTimeMillis();    }    // implement toString() for Point    // include the fields added in the aspect file    public String Point.toString() {        return String.format(                "Point: {name=%s, x=%d; y=%d, created=%d, updated=%d}",                getName(), getX(), getY(), created, lastUpdated);    }

Finally, we add two pointcut first-level advice, each implementing the assignment after the point constructor is called created , and calling setx (int), set (int), and SetName (string) Update the lastupdated member variable (this is used to !within(PointAspect) exclude the call to set* in the aspect script):

    // pointcut the constructor, and set the value for created    after() returning(Point p) : call(Point.new(..)) && !within(PointAspect) {        System.out.println(thisJoinPointStaticPart);        System.out.println("Set created");        p.created = System.currentTimeMillis();    }    // define a pointcut for setX and setY    pointcut update(Point p): target(p) && call(void Point.set*(..));    // make the lastUpdated updated every time    // setX or setY invoked    after(Point p): update(p) && !within(PointAspect) {        System.out.println("set updated for Point due to " + thisJoinPointStaticPart);        p.setUpdated();    }

Again, we can create a new unit test class to test:

package cc.databus.aspect.intertype;import org.junit.Test;public class TestPointAspect {    @Test    public void test() {        Point point = new Point(1,1);        point.setName("test");        point.setX(12);        point.setY(123);        System.out.println(point);    }}

To run the test, we can see the following results:

call(cc.databus.aspect.intertype.Point(int, int))Set createdset updated for Point due to call(void cc.databus.aspect.intertype.Point.setName(String))set updated for Point due to call(void cc.databus.aspect.intertype.Point.setX(int))set updated for Point due to call(void cc.databus.aspect.intertype.Point.setY(int))Point: {name=test, x=12; y=123, created=1536153649547, updated=1536153649548}

As you can see, both the member object and the member method injected through aspect are working.

Summarize

ITD is truly a powerful feature that allows you to inject new functionality into existing classes. However, I think that using this method is relatively error-prone, especially in the case of large projects, if through a large number of aspect scripts to achieve the function, I believe that the maintenance of the latter is a great challenge. Therefore, I suggest that in the absence of the spring framework to support the case, do not use this method a lot of blood for the project.

Reference
    1. Advanced AspectJ Part Ii:inter-type declaration
    2. Inter-type declarations

Article sync posted on my personal blog jianyuan.me, welcome to shoot bricks.
Portal: Inter-type declarations in ASPECTJ (member injection)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.