> For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gpcoder.gitbook.io/clean-code/bonus/aop-aspect-oriented-programming/building-an-aop-framework.md).

# 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="/files/M7mwSjmjmK0ZwfAbWYb1" 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 %}
