[JAVA] The times may come? Aspect Oriented Programming, What is the AspectJ Language?

Introduction

At the seminar, I had the opportunity to present my research in my area of interest. There were no papers that seemed interesting even after various researches, and the only thing that seemed interesting was aspect-oriented programming. It's a very old technology, so I think many people already know it or aren't interested in it, but I found it interesting, so I would like to introduce it. I hope anyone who reads this article is interested in aspect-oriented programming.

What is aspect-oriented programming?

Introduced as post-object-oriented, the next technology after object-oriented But that's not the case, aspect-oriented is a technology that fills the ** limits of object-orientation ** and develops it further.

In the first place contradiction in software engineering

In software, it is better to have a high degree of cohesion and a low degree of coupling. However, this is in the opposite direction in the first place If you like a program with a high degree of cohesion, you can create a function for each function. If you want a program with a low degree of coupling, you can combine the functions into one. I think that the change in the programming paradigm, such as functional and object-oriented, is linked to the change in where these midpoints are placed.

qiita2.PNG

Where did you put aspect-oriented programming?

I think object-oriented is a paradigm with a high degree of cohesion. One module is used as a class, many modules are created, and one module is called from one module. This will increase the degree of coupling One technique to reduce this degree of coupling is the GoF design pattern. Aspect-oriented programming has a high degree of cohesion and low coupling, so if you divide it into modules when writing and make one module when compiling, the degree of cohesion is high and the coupling can be kept low. Was started

qiita.PNG

** Aspect-oriented first idea **

ce843e51-632c-0e74-689d-3affd704ff1c.png

Why Aspect Oriented Is Effective

The code to satisfy a particular quality desire when creating software is often scattered across the basic modular structure of a program. Logging is often mentioned as an example, and the code that spits out logs for testing and security is written in various classes (modules). This is a cross-cutting concern, and if left cross-cutting rather than modularized, quality needs may be satisfied, but the overall program's visibility may be compromised, resulting in poor development efficiency and maintainability. is there Aspect-oriented programming is one of the effective technologies for modularizing cross-cutting concerns.

キャプチャ.PNG キャプチャ2.PNG

What is the separation of concerns?

Concern is a class that summarizes processes (methods) in computer science terms. The principle of separating programs into different modules for each concern is called Separation of Concerns. Separation is the collection of code related to each concern and separation from other code as an independent module. Different modules for different interests make it easier to extend or modify your program Aspect-oriented allows the separation of concerns from multiple perspectives that object-oriented was not possible

AspectJ A language that extends the Java language by adding an aspect-oriented programming paradigm Classes and aspects coexist, a little different from the main aspect-oriented programming A method of configuring modules (classes) from the perspective of the past and modularizing them with aspects if there are cross-cutting concerns.

A static join point model that thinks of a join point as a "place" Thinking of "time" is called a dynamic join point model. AspectJ uses a dynamic joinpoint model

aspect

Being like a class in Java In Java, classes describe members and methods together, In AspectJ, Aspect describes "advice", "pointcut", "intertype declaration", etc. together.

Aspect.java


import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before

@Aspect
public class Aspect {
  @before("execution(* hoge.*.*(..))")
  public void before() {
    System.out.println("before!");
  }
}

Aspect.java


public aspect GreetingAspect {
  pointcut message():
    call(* Messenger.printMessage(..));
  before(): message() {
    System.out.print("Hello, ");
  }
}

Point cut

Advice is set to call advice when the set method is called Pointcut determines whether the event that occurred when the method was called and the event that the advice is associated with match. (* The event is not actually occurring) Think of it like registering with an EventListener, such as when a button is clicked.

qiita4.PNG

Types of pointcuts

There are dynamic pointcuts and static pointcuts in pointcuts.

** Method-related pointcuts **

There are two pointcuts related to method calls: ** call ** and ** execution **. It takes a method pattern as an argument and represents the "time" when the method is called and executed.

Sample.java


call(void Main.init())
execution(void Main.init())
//Both of the above represent when the init method of the Main class is called.

:black_small_square:call A series of processing from when the execution thread of the program reaches the corresponding method call expression to when it executes the body of the called method and returns to the side of the call expression again.

:black_small_square:execution After the program execution thread moves into the body of the called method, a series of processing from the start to the end of the method body execution Processing done between the methods on which the execution thread is called

In general [Call selects the "when" when the method is called, and execution selects the "when" when the called method is executed] It is good to remember

854af01b-4ded-6512-3166-ba4c68a96d22.png

Difference between call and execution

Calling a non-static method using super is selected for execution, but not for call Call pointcuts are selected based on the superficial type that is called, while execution pointcuts are selected based on the true type of the object being called.

Setumei.java


/*Class part*/
interface Main {
  public abstract void init();
}
class Sub implements Main {
  public Sub() {

  }
  public void init() {

  }
}

/******************* call ***********************/
/*Aspect part*/
call(void Sub.init())

/*Execution part*/
Sub sub = new Sub();
Main s = sub;
sub.init();          //Be selected
s.init();            //Not selected
((Main)sub).init();  //Not selected

/************* execution ***********************/


/*Aspect part*/
execution(void Sub.init())

/*Execution part*/
sub.init();          //Be selected
s.init();            //Be selected
((Main)sub).init();  //Be selected

** Field-related pointcuts **

There are two field-related pointcuts, ** get ** and ** set **. It takes a field pattern as an argument and represents the "time" when the field is read or written.

Sample.java


//When referring to the value of the field named x in the int type of Person class
get(int Point.x)

//When a value is assigned to a field of any name whose non-private field type of Person class is String type
set(!private String Person.*)

//When a value is referenced in a field of any type and any name declared in any class interface
get(* *)

:black_small_square:get When you refer to (call) a field

:black_small_square:set When assigning a value to a field

** Constructor related pointcut **

There are four field-related pointcuts: ** call **, ** execution **, ** initialization **, and ** preinitialization **. Takes a constructor pattern as an argument and represents the "time" when an object is created with a matching constructor

Sample.java


call(public Point.new(int, int))
initialization(*.new(..))

:black_small_square:call While executing the new operator Until the execution thread of the program moves from the side executing the new operator to the body of the constructor and returns to the original side again after the execution is completed.

:black_small_square:execution After the other constructor calls by super or this have finished, while the first called constructor is actually running Not included while other constructors called by super or this are running

:black_small_square:initialization From the end of the constructor call by super to the end of the called constructor Unlike execution, this includes while calling and executing other constructors

:black_small_square:preinitialization From the time of the called constructor to just before executing the constructor call by super Includes time along the way to read another constructor with this and calculate the actual arguments of a call with this or super

qiita7.PNG

** Pointcut related to catch clause **

If an exception is thrown while the program is running, all running methods will be aborted prematurely To avoid this, try-catch can be used to write recovery processing from exceptions in the program.

A handler is provided for the pointcut related to the catch clause. Takes a type pattern as an argument and represents the "when" when the catch clause is executed

Sample.java


//Write the class name directly or use wildcards
handler(java.io.IOException+)

** Other pointcuts **

There are other point cuts, but they will be longer, so I summarized them separately. Please see if you want to specify in more detail List of pointcuts for finer pointcuts

advice

It's a function in an aspect, like a method in a class. Advice is inserted (weave) at the join point selected in the point cut. The join point represents the "time" when some processing is executed, but the "time" is not a moment but a period. You can choose when to give advice during that period

qiita12.PNG

As shown in the figure above, there is a period at the join point, and there are multiple places to incorporate advice.

Kind of advice

As explained above, the type of advice determines where to weave

** before advice **

The process to be executed immediately before (or at the start of) the period represented by the selected join point.

Example of before advice declaration

beforeAdvice.java


before(): loggedMethods() {
  System.out.println("** execute doIt() ...");
}

before advice starts with the keyword before Write the advice argument in parentheses before () Write an arbitrary pointcut between the colon of before (): and the curly braces of {}

Example of using before advice

beforeAdvide.java


pointcut pickup(BookSession bs, int i):
  call(String String.substring(int)) && this(bs) && args(i);

before(BookSession bs, int i): pickup(bs, i) {
  System.out.println("** substring(" + i + ")");
}

pickup Pointcut takes an argument, so advice also takes an argument You can pass that argument to the pointcut by writing before (BookSession bs, int i) pickup Pointcut assigns an appropriate value to the argument for each selected join point. The assigned value can be treated like a normal variable in the body of the advice.

** after advice **

The process to be executed immediately after (or at the end of) the institution represented by the selected join point.

after Example declaration of advice

afterAdvice.java


after(): loggedMethods() {
  System.out.println("** execute doIt() ...");
}

** after returning advice **

The process that is executed when the process for the period represented by the selected join point ends normally. If an exception is thrown in the middle and it terminates abnormally, it will not be executed.

after returning Advice declaration example

afterReturningAdvide.java


after() returning (String s):
  call(* *(..)) && within(BookSession)
{
  System.out.println("Returned Normally with " + s); 
}

After returning advice can be used in the body of the advice by extracting the return value when it ends normally.

** after throwing advice **

The process that is executed when the process of the period represented by the selected join point ends abnormally by throwing an exception.

After throwing Advice declaration example

afterThrowingAdvice.java


after() throwing (IOExecption e):
  call(* *(..)) && within(BookSession)
{
  System.out.println("Threw an exception " + e);
}

The throwing argument e is the value of the thrown exception and can be freely used in the advice body.

** around advice **

Performed instead of processing the entire duration of the selected join point If the join point calls the method, only the around advice will be executed, not the original method call at all. The description method is `return type around (argument example)` The return type must match the return type of the join point

Use example of around advice

Hello.java


aspect Overrider {
  int around(): call(int Hello.say()) {
    System.out.println("Hi");
    return 1;
  }
}

public class Hello {
  public static int say() {
    System.out.println("Hello");
    return 0;
  }
  public static void main(String[] args) {
    int i = say();
    System.out.println(i);
  }
}

Execution result

When there is around advice
Hi
1
When there is no around advice
Hello
0

Join point

Represents the "time" when some processing was executed The place where the original process is performed and the advice is woven, selected by the pointcut. Sometimes translated as a junction Think of it as an event that occurs during the execution of a program

qiita13.PNG

Intertype declaration

Aspect's ability to change the static structure of a program You can declare methods and feels for other classes and interfaces, rename them, and change other classes to implement additional new interfaces.

Intertype member declaration

Declaring members of other classes and interfaces in an aspect

[Inter] means [between] Declaration that straddles between a class or interface and an aspect That is why it is called an inter-type.

** Intertype method declaration **

Methods of other classes and interfaces can be declared within the aspect The difference from writing a normal method declaration is to write the class name or interface name in which the method is declared before the method name. Other than that, it's almost the same, you can also use this

Example of using intertype method declaration

Hello.java


aspect interTypeMethod {
  public void Hello.say() {
    System.out.println("Hi, I'm " + name);
  }
}

public class Hello {
  String name;
  
  Public Hello(String name) {
    this.name = name;
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

Execution example

Hi, I'm Taro

As you can see in the example, it is possible to call the say () method as declared in the Hello class. In the say () method, even the name field of Hello class is used. It's not too strange if you understand that weaving to the Hello class at compile time.

** Intertype method declaration to interface ** In the canonical Java language, only abstract methods can be declared in an interface However, intertype declarations allow you to declare non-abstract methods for your interfaces.

Hello.java


aspect interTypeMethod {
  public void Greeting.say() {
    System.out.println("Hi, I'm " + name);
  }
}

interface Greeting {

}

public class Hello implements Greeting {
  String name;
  
  Public Hello(String name) {
    this.name = name;
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

You can see that the interTypeMethod aspect declares the say () method in the Greeting interface. However, the Hello class that implements the Greeting interface does not override the say () method. As you can see, declaring a method on an interface with an aspect means declaring a non-static method.

** Intertype field declaration **

You can declare fields for classes and interfaces The canonical Java language does not allow you to declare non-final fields in an interface, Intertype declarations allow you to declare non-final fields

Hello.java


aspect interTypeField {
  private String Hello.name;
}

public class Hello {
  Public Hello(String name) {
    this.name = name;
  }
  public void say() {
    System.out.println("Hi, I'm " + name);
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

** Intertype constructor declaration **

Can declare constructors for classes and interfaces Even with the intertype declaration, it is not possible to declare the constructor of the interface. It is possible to use this and super () in the intertype constructor declaration

Hello.java


aspect interTypeField {
  Public Hello.new(String name) {
    this.name = name;
  }
}

public class Hello {
  String name;

  public void say() {
    System.out.println("Hi, I'm " + name);
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

Finally

Thank you for watching until the end. I'm not a specialist in aspect-oriented programming, so I think I made a lot of mistakes. The contents of the investigation are also old, so I think there are some differences from the current situation. All the content I chose this time is my own judgment and prejudice. There are many other great features in AspectJ. Intertype declarations also have many access modifiers and class inheritance changes. I would like to write more details in another article. Thank you for watching until the end. I hope you read this article and get interested in aspect-oriented programming. Please note that there are many mistakes and mistakes.

reference

Recommended Posts

The times may come? Aspect Oriented Programming, What is the AspectJ Language?
What is programming?
What is different from the PHP language. [Note]
What is object-oriented programming? ~ Beginners ~
What is the pluck method?
What is the BufferedReader class?
About the programming language Crystal
What is the constructor for?
What is the initialize method?
'% 02d' What is the percentage of% 2?
What is a snippet in programming?
[Technical Note] What is Object Oriented?