AOP详细介绍

简介: AOP(Aspect-Oriented Programming)是一种编程范式,旨在通过将横切逻辑(cross-cutting concerns)从核心业务逻辑中分离出来,以提高代码的可维护性和可重用性。在Java中,AOP可以通过动态代理来实现。

下面我们来深度解析AOP的底层原理,并且带有源码示例。

  1. JDK动态代理实现AOP:JDK动态代理基于接口,要求目标对象实现一个接口。它使用Java的反射机制在运行时动态创建代理对象。JDK动态代理主要涉及以下几个类和接口:
  • InvocationHandler(接口):定义了一个invoke方法,它是实际代理逻辑的入口。
  • Proxy(类):提供了创建代理对象的静态方法,它会生成一个代理类的字节码,并通过反射机制创建代理对象。

下面是一个使用JDK动态代理实现AOP的示例代码:

// 定义一个接口
public interface UserService {
    void save();
}
// 实现接口的目标对象
public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("保存用户信息");
    }
}
// 自定义InvocationHandler
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始事务");
        Object result = method.invoke(target, args);
        System.out.println("提交事务");
        return result;
    }
}
// 使用JDK动态代理
public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        proxy.save();
    }
}

在上面的示例中,我们定义了一个UserService接口和一个UserServiceImpl类作为目标对象,然后通过自定义MyInvocationHandler类来实现代理逻辑。在invoke方法中,我们可以添加额外的横切逻辑,比如开始事务和提交事务。

  1. CGLIB动态代理实现AOP:CGLIB(Code Generation Library)是一个基于字节码生成的库,可以代理没有实现接口的类。CGLIB动态代理通过继承的方式来创建代理对象,并重写目标对象的方法。CGLIB动态代理主要涉及以下几个类:
  • MethodInterceptor(接口):定义了一个intercept方法,它是实际代理逻辑的入口。
  • Enhancer(类):提供了创建代理对象的静态方法,它会生成一个代理类的字节码,并通过字节码增强技术创建代理对象。

下面是一个使用CGLIB动态代理实现AOP的示例代码:

// 目标对象
public class UserService {
    public void save() {
        System.out.println("保存用户信息");
    }
}
// 自定义MethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("提交事务");
        return result;
    }
}
// 使用CGLIB动态代理
public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new MyMethodInterceptor());
        UserService proxy = (UserService) enhancer.create();
        proxy.save();
    }
}

在上面的示例中,我们创建了一个UserService类作为目标对象,然后通过自定义MyMethodInterceptor类来实现代理逻辑。在intercept方法中,我们可以添加额外的横切逻辑,比如开始事务和提交事务。

总结:JDK动态代理和CGLIB动态代理是两种常见的实现AOP的方式。选择使用哪种方式应根据具体需求和场景来决定。如果目标对象实现了接口,可以使用JDK动态代理;如果目标对象没有实现接口,可以使用CGLIB动态代理。

目录
相关文章
|
4月前
AOP&面向切面编程
AOP&面向切面编程
55 0
|
4月前
|
安全 Python
AOP 面向切面编程
AOP 面向切面编程
30 0
|
9月前
|
XML Java 数据格式
三、AOP(二)
三、AOP(二)
52 0
|
7月前
|
Java 编译器 Maven
AOP
底层实现方式之一是代理,由代理结合通知和目标,提供增强功能 除此以外,aspectj 提供了两种另外的 AOP 底层实现: 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中 第二种是通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能 作为对比,代理是运行时生成新的字节码 简单比较的话: aspectj 在编译和加载时,修改目标字节码,性能较高 aspectj 因为不用代理,能突破一些技术上的限制,例如对构造、对静态方法、对 final 也能增强 但 aspectj 侵入性较强,且需要学习新的 aspectj 特有语
43 1
|
9月前
|
XML Java 数据格式
三、AOP(一)
三、AOP(一)
51 0
三、AOP(一)
|
10月前
|
监控 Java 数据安全/隐私保护
什么是AOP?
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,通过将横切关注点(Cross-cutting Concerns)从核心业务逻辑中分离出来,使得代码的组织结构更清晰,易于维护和扩展。
185 0
|
12月前
|
Java Spring
实现一个简单的AOP
实现一个简单的AOP
|
数据安全/隐私保护
你不是说你会Aop吗?
你不是说你会Aop吗?
97 0
|
XML Java 数据安全/隐私保护
浅谈AOP以及AspectJ和Spring AOP
AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如日志收集、事务管理、安全检查、缓存、对象池管理等。AOP实现的关键就在于AOP框架自动创建的AOP代理,AOP代理则可分为静态代理和动态代理两大类,其中静态代理是指使用AOP框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于`JDK动态代理`、`CGLIB`等在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强。
1919 0
Aop说明
在xml配置中用到那个标签在开启不然不用,他会报错 1.对接口进行动态代理:创建出来的对象必须转换成接口类型                                          原因他创建的是实现类而不是不是接口所以实现的时候必须转换成接口                     ...
880 0