90人参与 • 2025-03-10 • Java
在java中,切面编程(aspect-oriented programming, aop)是一种编程范式,用于将横切关注点(如日志记录、事务管理、安全性等)从业务逻辑中分离出来。aop通过将这些关注点模块化为“切面”,使代码更易于维护和扩展。
切面(aspect):一个切面是一个模块化的关注点集合,它包含了多个通知和切入点的定义。例如,日志切面会定义在哪些方法执行前后进行日志记录。
通知(advice):通知定义了在切入点执行时要执行的代码逻辑,也就是在特定的连接点上执行的操作。常见的通知类型有前置通知、后置通知、环绕通知等。
切入点(pointcut):切入点用于定义哪些连接点(程序执行过程中的特定位置,如方法调用、异常抛出等)会触发通知的执行。它可以通过方法名、类名、参数类型等条件进行精确匹配。
连接点(join point):连接点是程序执行过程中可以插入切面的点,例如方法调用、字段访问等。在 java 中,主要的连接点通常是方法调用。
1.基于代理的 aop 实现(如 spring aop)
原理:spring aop 默认使用代理模式来实现 aop 功能,有两种代理方式:jdk 动态代理和 cglib 代理。
jdk 动态代理:当目标对象实现了接口时,spring aop 会使用 jdk 动态代理。它基于 java 的 java.lang.reflect.proxy 类和 java.lang.reflect.invocationhandler 接口。在运行时,jdk 动态代理会根据目标对象实现的接口动态生成一个代理类,该代理类实现了与目标对象相同的接口。当调用代理对象的方法时,会触发 invocationhandler 的 invoke() 方法,在该方法中可以插入切面逻辑。
cglib 代理:当目标对象没有实现接口时,spring aop 会使用 cglib 代理。cglib(code generation library)是一个强大的、高性能的代码生成库,它通过继承目标对象的类来创建代理对象。在运行时,cglib 会动态生成一个目标对象的子类,并重写目标对象的方法,在重写的方法中插入切面逻辑。
代码如下:
import org.springframework.aop.methodbeforeadvice;
import org.springframework.aop.framework.proxyfactory;
import java.lang.reflect.method;
// 定义业务接口
interface businessservice {
void dobusiness();
}
// 实现业务接口
class businessserviceimpl implements businessservice {
@override
public void dobusiness() {
system.out.println("执行核心业务逻辑");
}
}
// 定义前置通知
class mybeforeadvice implements methodbeforeadvice {
@override
public void before(method method, object[] args, object target) throws throwable {
system.out.println("前置通知:在方法执行前记录日志");
}
}
public class aopproxyexample {
public static void main(string[] args) {
// 创建目标对象
businessservice target = new businessserviceimpl();
// 创建前置通知对象
mybeforeadvice advice = new mybeforeadvice();
// 创建代理工厂
proxyfactory proxyfactory = new proxyfactory();
// 设置目标对象
proxyfactory.settarget(target);
// 添加通知
proxyfactory.addadvice(advice);
// 获取代理对象
businessservice proxy = (businessservice) proxyfactory.getproxy();
// 调用代理对象的方法
proxy.dobusiness();
}
}
原理:aspectj 是一个功能强大的 aop 框架,它采用字节码增强的方式来实现 aop。在编译时或类加载时,aspectj 会修改目标类的字节码,将切面逻辑直接插入到目标类的方法中。与基于代理的实现方式不同,字节码增强不需要创建代理对象,而是直接在目标类的字节码中添加切面代码,因此性能更高,并且可以处理更多的连接点。
编译时织入:在编译 java 源代码时,aspectj 编译器(ajc)会对源代码进行处理,将切面逻辑织入到目标类的字节码中。这种方式需要使用 aspectj 编译器来编译代码。
类加载时织入:在类加载时,通过 java 的类加载器对目标类的字节码进行修改,将切面逻辑织入其中。这种方式不需要使用 aspectj 编译器,只需要在运行时配置类加载器即可。
代码如下:
import org.aspectj.lang.joinpoint;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.before;
import org.aspectj.lang.annotation.pointcut;
// 定义切面类
@aspect
public class loggingaspect {
// 定义切入点
@pointcut("execution(* com.example.businessservice.*(..))")
public void businessservicemethods() {}
// 定义前置通知
@before("businessservicemethods()")
public void beforebusinessservicemethod(joinpoint joinpoint) {
system.out.println("前置通知:在方法执行前记录日志,方法名:" + joinpoint.getsignature().getname());
}
}
// 定义业务类
class businessservice {
public void dobusiness() {
system.out.println("执行核心业务逻辑");
}
}
public class aspectjexample {
public static void main(string[] args) {
businessservice service = new businessservice();
service.dobusiness();
}
}
到此这篇关于java中切面的使用方法的文章就介绍到这了,更多相关java中切面使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论