# Building an AOP framework

In the example below we will write our own code to create AOP Framework using JDK Proxy without using any third-party libraries.

To use JDK Proxy we perform the following steps:

* Create Invocation Handler: this class must implemnet java.lang.reflect.InvocationHandler. InvocationHandler is the interface implemented by the invocation handler of a proxy instance. When a method is called on a proxy instance, the method call is encrypted and sent to its invocation handler's calling method.
* Create Proxy Instance : use Proxy.newProxyInstance() method provided by java.lang.reflect.Proxy factory method.

For example, we need to add some handling before and after the methods in the AccountService class are called.

<figure><img src="https://2690823695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfnxBXXXtPb2q20LXB7uL%2Fuploads%2FP58SqY5qL2l5wHOBcp58%2Fimage.png?alt=media&#x26;token=e6b1277a-64e2-48e8-b077-13547bfc672b" alt=""><figcaption></figcaption></figure>

Create Domain class.

{% hint style="success" %}

```java
package com.gpcoder.aop.account;
 
import lombok.AllArgsConstructor;
import lombok.Data;
 
@Data
@AllArgsConstructor
public class Account {
 
    private String owner;
    private String currency;
    private int balance;
}
```

{% endhint %}

Create business classes:

{% hint style="success" %}

```java
package com.gpcoder.aop.account;
 
public interface AccountService {
 
    void addAccount(Account account);
 
    void removeAccount(Account account);
 
    int getSize();
}
```

{% endhint %}

{% hint style="success" %}

```java
package com.gpcoder.aop.account;
 
import java.util.ArrayList;
import java.util.List;
 
public class AccountServiceImpl implements AccountService {
 
    private List<Account> accounts = new ArrayList<>();
 
    @Override
    public void addAccount(Account account) {
        System.out.println("addAccount: " + account);
        accounts.add(account);
    }
 
    @Override
    public void removeAccount(Account account) {
        System.out.println("removeAccount: " + account);
        accounts.remove(account);
    }
 
    @Override
    public int getSize() {
        System.out.println("getSize: " + accounts.size());
        return accounts.size();
    }
}
```

{% endhint %}

Create cross-cutting concern classes:

{% hint style="success" %}

```java
package com.gpcoder.aop.handler;
 
import java.lang.reflect.InvocationHandler;
 
public abstract class AbstractHandler implements InvocationHandler {
 
    private Object targetObject;
 
    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }
 
    public Object getTargetObject() {
        return targetObject;
    }
}
```

{% endhint %}

{% hint style="success" %}

```java
package com.gpcoder.aop.handler;
 
import java.lang.reflect.Method;
 
/**
 * The class BeforeHandler provides a template for the before execution
 */
public abstract class BeforeHandler extends AbstractHandler {
 
    /**
     * Handles before execution of actual method.
     */
    public abstract void handleBefore(Object proxy, Method method, Object[] args);
 
    /*
     * (non-Javadoc)
     *
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
     * java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        handleBefore(proxy, method, args);
        return method.invoke(getTargetObject(), args);
    }
}
```

{% endhint %}

{% hint style="success" %}

```java
package com.gpcoder.aop.handler.impl;
 
import java.lang.reflect.Method;
 
import com.gpcoder.aop.handler.BeforeHandler;
 
/**
 * This class provides implementation before actual execution of method.
 */
public class BeforeHandlerImpl extends BeforeHandler {
 
    @Override
    public void handleBefore(Object proxy, Method method, Object[] args) {
        // Provide your own cross cutting concern
        System.out.println("Handling before actual method execution");
    }
}
```

{% endhint %}

{% hint style="success" %}

```java
package com.gpcoder.aop.handler;
 
import java.lang.reflect.Method;
 
public abstract class AfterHandler extends AbstractHandler {
 
    /**
     * Handles after the execution of method.
     */
    public abstract void handleAfter(Object proxy, Method method, Object[] args);
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(getTargetObject(), args);
        handleAfter(proxy, method, args);
        return result;
    }
}
```

{% endhint %}

{% hint style="success" %}

```java
package com.gpcoder.aop.handler.impl;
 
import java.lang.reflect.Method;
 
import com.gpcoder.aop.handler.AfterHandler;
 
/**
 * This class provides an implementation of business logic which will be
 * executed after the actual method execution.
 */
public class AfterHandlerImpl extends AfterHandler {
 
    @Override
    public void handleAfter(Object proxy, Method method, Object[] args) {
        // Provide your own cross cutting concern
        System.out.println("Handling after actual method execution");
        System.out.println("---");
    }
}
```

{% endhint %}

Create AOP proxy-based class:

{% hint style="success" %}

```java
package com.gpcoder.aop.handler;
 
import java.lang.reflect.Proxy;
import java.util.List;
 
/**
 * A factory for creating Proxy objects.
 */
public class ProxyFactory {
 
    private ProxyFactory() {
        throw new UnsupportedOperationException();
    }
 
    public static Object getProxy(Object targetObject, List<AbstractHandler> handlers) {
        if (handlers != null && !handlers.isEmpty()) {
            Object proxyObject = targetObject;
            for (AbstractHandler handler : handlers) {
                handler.setTargetObject(proxyObject);
                proxyObject = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                        targetObject.getClass().getInterfaces(), handler);
            }
            return proxyObject;
        }
 
        return targetObject;
    }
}
```

{% endhint %}

Create application:

{% hint style="success" %}

```java
package com.gpcoder.aop;
 
import java.util.ArrayList;
import java.util.List;
 
import com.gpcoder.aop.account.Account;
import com.gpcoder.aop.account.AccountService;
import com.gpcoder.aop.account.AccountServiceImpl;
import com.gpcoder.aop.handler.AbstractHandler;
import com.gpcoder.aop.handler.ProxyFactory;
import com.gpcoder.aop.handler.impl.AfterHandlerImpl;
import com.gpcoder.aop.handler.impl.BeforeHandlerImpl;
 
/**
 * This class to verify an AOP example using JDK proxy.
 */
public class AspectOrientedProgrammingInJdkExample {
 
    public static void main(String[] args) {
 
        List<AbstractHandler> handlers = new ArrayList<>();
        handlers.add(new BeforeHandlerImpl());
        handlers.add(new AfterHandlerImpl());
 
        AccountService proxy = (AccountService) ProxyFactory.getProxy(new AccountServiceImpl(), handlers);
        Account account = new Account("gpcoder", "USD", 100);
        proxy.addAccount(account);
        proxy.getSize();
        proxy.removeAccount(account);
        proxy.getSize();
    }
}
```

{% endhint %}

Output:

{% hint style="success" %}

```java
Handling before actual method execution
addAccount: Account(owner=gpcoder, currency=USD, balance=100)
Handling after actual method execution
---
Handling before actual method execution
getSize: 1
Handling after actual method execution
---
Handling before actual method execution
removeAccount: Account(owner=gpcoder, currency=USD, balance=100)
Handling after actual method execution
---
Handling before actual method execution
getSize: 0
Handling after actual method execution
---
```

{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gpcoder.gitbook.io/clean-code/bonus/aop-aspect-oriented-programming/building-an-aop-framework.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
