手写Aop

本文介绍了AOP的概念及其在系统增强中的作用,详细讲解了基于Java动态代理的AOP实现,包括JDK和CGLIB代理的原理。通过创建自定义注解、切面类、功能类和核心容器类,展示了如何手工实现AOP的Before、After和Exception增强。文中还提供了完整的代码示例,帮助读者深入理解AOP的工作机制。

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

手写简单Aop,展示aop设计思路和基础原理

提示:本文章适合有一定java反射基础的程序员,博主还是个新手新手超新手,欢迎指正!!!本文是参考Java 编程逻辑一书…


Aop 简介:

简介百度一大堆,这里简单说下博主自己的理解,Aop其实就是用来解决成品系统中添加辅助功能的一种方式。当你的系统所有功能都完成了,你调试 的时候发现没有日志,调试很不方便时,你想添加日志功能上去,但是现在所有的 功能都已经做完。你给每个功能都添加日志时,就会有大量的工作,这种硬编码的方式太过笨重,于是就有人提出了aop的方式。它时通过动态代理为需要增强功能的类生成一个代理类,这个代理可以在功能方法执行前后执行额外的新增功能。同时它和之前的功能逻辑相分离,代码优雅。以松耦合的方式完成了功能的增强。Aop 主要应用于日志、性能监控、权限检查,数据库事务


提示:以下是本篇文章正文内容,下面案例可供参考

一、Aop 的基础原理是动态代理,动态代理又有哪些呢?

1. JDK 代理:
JDK代理面向的是一组接口,它为这些接口动态的创建了一个实现类 ,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,也就是说其背后不一定有真正被代理的对象,也可能有多个实际对象,根据情况动态选择。

2. CGLIB 代理:
CGLIB 是第三方的类库。它面向的是一个具体的类。它动态的 创建了一个新类,继承了具体的类,重写了它的方法。Aop是有CGLIB来实现的。

二、手写Aop实例

1.创建自定义注解

代码如下(示例):

/**
 * 切面注解
 * @author 9699
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aspect {
    Class<?>[] values();
}
/**
 * 依赖注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Inject {
}

/**
 * 在xx之前执行注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Before {
}

/**
 * 在xx执行之后注解
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface After {
}

/**
 * 出现异常时标记注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Exception {
}

2.创建切面类

代码如下(示例):

package Proxy.MineExerciseAop;

import java.lang.reflect.Method;

/**
 * 增加日志切面类
 */
@Aspect(values = {OrdinaryServiceA.class, OrdinaryServiceB.class})
public class InfixLogAspect {

    @Before
    public static void before(Object object, Method method,Object[] args){
        if(method == null){
            System.out.println("方法为空");
        }
        System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
                "当前执行方法:" + method.getName());
    }

    @After
    public static void after(Object object, Method method, Object[] args, Object result){
        System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
                "当前执行方法:" + method.getName());
    }
}

/**
 *异常切面增强类
 */
@Aspect(values = OrdinaryServiceB.class)
public class InfixExceptionAspect {

    @Exception
    public static void exception(Object object, Method method, Object [] args, Throwable e){
        System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
                "当前执行方法:" + method.getName());
    }

}


3.创建功能类

代码如下(示例):

/**
 * 功能类A
 */
public class OrdinaryServiceA {

    @Inject
    private OrdinaryServiceB ordinaryServiceB;

    public OrdinaryServiceA() {

    }

    public void action(){
        ordinaryServiceB.writeLog();
    }
}

/**
 * 功能类B
 */
public class OrdinaryServiceB {

    public void writeLog(){
        System.out.println("当前类的第一个方法: " + this.getClass().getMethods()[0].getName());
    }
}

4.创建增强方法类型枚举

代码如下(示例):

/**
 * 切面增强方法类型
 */
public enum  InterceptPoint {
    BEFORE,AFTER,EXCEPTION
}

5.创建核心容器类

代码如下(示例):

package Proxy.MineExerciseAop;


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * DI容器,aop动态代理核心逻辑
 *1.当调用静态方法getInstance(),会先加载静态属性和静态代码块,将切点方法添加到静态注册容器中
 * 当生成cglib代理类后,调用方法时,会跳到动态代理方法intercept()方法中,执行实例对象目标方法
 */
public class MineCglibContainer {

    //1.切点方法静态注册容器
    static  Map<Class<?>, Map<InterceptPoint, List<Method>>> interceptMethodsMap = new HashMap<>();

    //1.切面类集合,本来是要扫描包下所有类,找到有切面注解的类在添加到该切面容器中,现在简化为直接手动添入
    static List<Class<?>> aspects = new ArrayList<>(Arrays.asList(
            new Class<?> []{InfixLogAspect.class, InfixExceptionAspect.class}));
    //1.静态注入数据
    static{
        init();
    }

    //初始化数据
    private static void init() {
        for (Class<?> cls: aspects) {
            Aspect aspect = cls.getAnnotation(Aspect.class);
            if(aspect != null){
                Class<?> [] interceptCls = aspect.values();
                for (Class<?> incs: interceptCls) {
                    Method [] methods = cls.getDeclaredMethods();
                    for (Method method:methods) {
                        if(method.isAnnotationPresent(Before.class)){
                            addInterceptMethod(incs, InterceptPoint.BEFORE,method);
                        }else if(method.isAnnotationPresent(After.class)){
                            addInterceptMethod(incs, InterceptPoint.AFTER,method);
                        }else if(method.isAnnotationPresent(Exception.class)){
                            addInterceptMethod(incs, InterceptPoint.EXCEPTION,method);
                        }
                    }
                }
            }
        }
    }

    //向容器添加切点方法数据
    public static void addInterceptMethod(Class<?> cls,InterceptPoint point,Method  method){
        if(method == null){
            return;
        }
        Map<InterceptPoint,List<Method>> map = interceptMethodsMap.get(cls);
        if(map == null){
            map = new HashMap<>();
            interceptMethodsMap.put(cls,map);
        }
        List<Method> methodList = map.get(point);
        if(methodList == null){
            methodList = new ArrayList<>();
            map.put(point,methodList);
        }
        methodList.add(method);
    }

     //CGLIB 动态代理逻辑
     static class MineInterceptor implements MethodInterceptor{

         @Override
         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws InvocationTargetException, IllegalAccessException {
             Object result = null;
             //执行before注解方法
             try {
                 List<Method> beforeMethods = getInterceptMethod(o.getClass().getSuperclass(), InterceptPoint.BEFORE);
                 for (Method me : beforeMethods) {
                     me.invoke(null, o, method, objects);
                 }
                 //执行目标方法
                  result = methodProxy.invokeSuper(o, objects);
                 //执行after注解方法
                 List<Method> afterMethods = getInterceptMethod(o.getClass().getSuperclass(), InterceptPoint.AFTER);
                 for (Method me : afterMethods) {
                     me.invoke(null, o, method, objects,result);
                 }
             }catch (Throwable e){
                 e.printStackTrace();
                 List<Method> exceptionMethods = getInterceptMethod(o.getClass().getSuperclass(),InterceptPoint.EXCEPTION);
                 for (Method me: exceptionMethods) {
                     me.invoke(null,o,method,objects,e);
                 }
             }
             return result;
         }
     }

     //获取静态切点方法容器中的方法
     public static List<Method> getInterceptMethod(Class<?> cls, InterceptPoint point){
        Map<InterceptPoint,List<Method>> map = interceptMethodsMap.get(cls);
        if(map == null){
            return Collections.emptyList();
        }
        List<Method> methods = map.get(point);
        if(methods == null){
            return Collections.emptyList();
        }
        return methods;
     }

     //获取对象,DI依赖
    public static <T> T getInstance(Class<?> cls) throws IllegalAccessException, InstantiationException {

        //生成对象
        Object o = createInstance(cls);
        //获取本类所有属性
        Field [] fields = cls.getDeclaredFields();
        for (Field field: fields) {
            //判断是否有依赖注解
            if(field.isAnnotationPresent(Inject.class)){
                //判断属性是否有读写权限
                if(!field.isAccessible()){
                    //给属性设置读写权限
                    field.setAccessible(true);
                }
                //获取属性类型
                Class<?> fieldType = field.getType();
                //设置属性值
                field.set(o,getInstance(fieldType));
            }
        }
       return (T)o;
    }

     //创建对象
    public static <T> T createInstance(Class<?> cls) throws IllegalAccessException, InstantiationException {

        if(!interceptMethodsMap.containsKey(cls)){
            return (T) cls.newInstance();
        }

        //cglib 代理增强类,相当于jdk 代理的Proxy
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(cls);
        //设置回调
        enhancer.setCallback(new MineInterceptor());
        //创建代理类对象
        return (T) enhancer.create();
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        OrdinaryServiceA proxyA = MineCglibContainer.getInstance(OrdinaryServiceA.class);
        proxyA.action();
    }
}

总结

这是博主写的第一篇文章,在大牛们面前献丑了!!希望大佬们多多指正,小菜我会再接再厉的。本文借鉴自java逻辑编程一书,这本书写的很不错,适合新手的进阶书籍。看了这本书,小菜java基础更上了一层楼,在这里推荐一下。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值