想要环绕拦截一个 Solon  Bean 的函数（AOP）。需要三个前置条件：

1. 通过注解做为“切点”，进行拦截（不能无缘无故给拦了吧？费性能）
2. Bean 的 method 是被代理的（比如 @Controller、@Remoting、@Component 注解的类）
3. 在 Bean 被扫描之前，完成拦截器的注册


被代理的 method，最后会包装成 MethodWrap。其中 invokeByAspect 接口，提供了环绕拦截支持：

<img src="/img/59a4f8512ebb493ea86d44cd27fdcbc8.png" width="400" />


### 1、定义切点和注册拦截器

Solon 的切点，通过注解实现，得先定义一个。例如：`@Transaction`

```java
//
// @Target 是决定可以注在什么上面的！！！
//
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transaction { ... }
```

定义拦截器

```java
import org.noear.solon.core.aspect.Invocation;
import org.noear.solon.core.aspect.MethodInterceptor;

public class TranInterceptor implements MethodInterceptor {
    @Override
    public Object doIntercept(Invocation inv) throws Throwable {
        AtomicReference val0 = new AtomicReference();

        Transaction anno = inv.method().getAnnotation(Transaction.class);
        TranUtils.execute(anno, () -> {
            val0.set(inv.invoke());
        });

        return val0.get();
    }
}
```

手动注册拦截器：（必须要在扫描之前，完成注册）


```java
import org.noear.solon.Solon;
import org.noear.solon.core.AppContext;
import org.noear.solon.data.annotation.Transaction;
import org.noear.solon.data.tran.interceptor.TranInterceptor;

//比如在应用启动时
public class App{ 
    public static void main(String[] args){
        Solon.start(App.class, args, app->{
            app.context().beanInterceptorAdd(Transaction.class, new TranInterceptor());
        });
    }
}

//比如在插件启动时
public class PluginImpl impl Plugin{
    public void start(AppContext context){
        context.beanInterceptorAdd(Transaction.class, new TranInterceptor());
    }
}

//或者别的时机点（可以看一下应用生命周期）
```

也可以"免"手动注册拦截器（即，不用注册直接可用）：通过 [@Around 注解继承](/article/619)

```java
import org.noear.solon.annotation.Around;
import org.noear.solon.data.tran.interceptor.TranInterceptor;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Around(TranInterceptor.class)
public @interface Transaction { ... }
```


现在切点定义好了，可以到处“埋”点了...


### 2、应用：把切点“埋”到需要的地方

```java
import org.noear.solon.annotation.Component;
import org.noear.solon.data.annotation.Transaction;

@Component
public class DemoService{
    @Transaction //注到函数上（仅对当前函数有效）
    public void addUser(UserModel user){
        //...
    }
}

@Transaction //注到类上（对所有函数有效）
@Component
public class DemoService{
    public void addUser(UserModel user){
        //...
    }
}
```

就这样完成一个AOP的开发案例。


### 3、通过插件及插件配置，变成一个复用的东西

这是刚才定义注解和拦截器：

```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transaction { ... }


public class TranInterceptor implements MethodInterceptor { ... }
```

开发插件：
```java
import org.noear.solon.core.AppContext;
import org.noear.solon.core.Plugin;

public class XPluginImpl implements Plugin {
    public void start(AppContext context){
        context.beanInterceptorAdd(Transaction.class, new TranInterceptor());
    }
}
```

配置插件：

```ini
solon.plugin=xxx.xxx.log.XPluginImpl
```

一个可复用的插件开发完成了。关于Solon插件开发，可参考别的章节内容。

