JAVA实现简单的切面注解

本文探讨了Spring的Aspect机制,通过实现自定义aspect注解,演示了如何使用动态代理来捕获方法调用前后的行为,并打印参数和返回结果,为理解Spring切面的执行顺序提供了实践案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

今天在分析同事遇到一个springboot的注解和方法锁一起用而导致的问题(@Transaction和synchronized用在同一个方法中由于事务先于锁进入后于锁释放而可能引发的数据问题)中而突然思考到spring的Aspect是怎么样的执行顺序,本文介绍java中其中一种(InvocationHandler)利用动态代理的方式实现的代理的方法,从而类似的机制我们推测出spring的切面其实也是在代理类中执行了切面的函数并在invoke之前或者之后去执行定义的点,而之所以能够自动扫描切面应该是类似spring rabbitmq的实现扫面一遍所有的component bean获取所有的注解然后执行,后续再仔细分析Aspect的实现,本文我们尝试实现aspect注解从而实现捕获函数执行前参数和执行后结果并打印出来

代码

package com.oujiangping.leetcode;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface aspect {
}
package com.oujiangping.leetcode;

@aspect
public interface TestAspect {
    public String test(String sr);
}

package com.oujiangping.leetcode;

@aspect
public class TestAspectImpl implements TestAspect {
    @Override
    public String test(String sr) {
        System.out.println("run TestAspectImpl.test " + sr);
        return sr;
    }
}

package com.oujiangping.leetcode;

@aspect
public class TestAspectImplA implements TestAspect {
    @Override
    public String test(String sr) {
        System.out.println("run TestAspectImplA.test " + sr);
        return sr;
    }
}

package com.oujiangping.leetcode;
package com.oujiangping.leetcode;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyAspect implements InvocationHandler {
    Object instance;

    public Object aspect(Object instance) {
        this.instance = instance;
        return Proxy.newProxyInstance(instance.getClass().getClassLoader(), instance.getClass().getInterfaces(),this);
    }

    public void befor(Method method, Object[] args) {
        System.out.println("~~~~ befor: " + method.getName() + " " + args);
    }

    public void after(Object object) {
        System.out.println("~~~~ after: " + object);
    }

    public static void init() {
        Field[] fields= MyAspect.class.getDeclaredFields();

        for(int i=0;i<fields.length;i++){
            MyAspect myAspect = new MyAspect();
            aspect aspects = fields[i].getType().getAnnotation(aspect.class);
            if(aspects != null) {
                fields[i].setAccessible(true);
                try {
                    fields[i].set(myAspect, new MyAspect().aspect(fields[i].get(myAspect)));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;
        befor(method, args);
        result = method.invoke(instance, args);
        after(result);
        return null;
    }

    public static TestAspect testAspect = new TestAspectImpl();
    public static TestAspect testAspectA = new TestAspectImplA();;

    public static void main(String []args) {
        init();
        testAspect.test("I'm TestAspectImpl");
        testAspectA.test("I'm TestAspectImplA");
    }
}


结果:
~~~~ befor: test [Ljava.lang.Object;@49476842
run TestAspectImpl.test I'm TestAspectImpl
~~~~ after: I'm TestAspectImpl
~~~~ befor: test [Ljava.lang.Object;@78308db1
run TestAspectImplA.test I'm TestAspectImplA
~~~~ after: I'm TestAspectImplA

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值