做空间的网站吗,关键词优化是什么意思,手机传奇网站模板下载,网站免费观看文章目录 1. Spring AOP与动态代理1.1 Spring AOP和动态代理的关系1.2 AOP基本术语 2. 通过XML配置实现Spring AOP2.1 添加Spring依赖2.2 定义业务接口和实现类2.3 定义切面类2.4 配置XML 1. Spring AOP与动态代理
1.1 Spring AOP和动态代理的关系 Spring AOP使用动态代理作为… 文章目录 1. Spring AOP与动态代理1.1 Spring AOP和动态代理的关系1.2 AOP基本术语 2. 通过XML配置实现Spring AOP2.1 添加Spring依赖2.2 定义业务接口和实现类2.3 定义切面类2.4 配置XML 1. Spring AOP与动态代理
1.1 Spring AOP和动态代理的关系 Spring AOP使用动态代理作为其主要机制来实现面向切面的编程。这种机制允许Spring在运行时动态地创建代理对象这些代理对象包装了目标对象即业务组件以便在调用目标对象的方法前后插入额外的行为如安全检查、事务管理、日志记录等。 JDK动态代理当目标对象实现了一个或多个接口时Spring AOP默认使用JDK的动态代理。JDK动态代理通过反射机制为接口创建一个代理对象这个代理对象会拦截对目标接口方法的所有调用。 CGLIB代理如果目标对象没有实现任何接口Spring AOP会退回到使用CGLIB库生成目标类的子类。CGLIBCode Generation Library是一个强大的高性能代码生成库它在运行时扩展了Java类并在子类中覆盖了方法来实现方法拦截。
无论使用哪种代理方式目的都是在不改变原有业务逻辑代码的基础上通过切面定义的通知在方法执行的不同阶段插入附加行为。
1.2 AOP基本术语 切面Aspect切面是面向切面编程的核心它是将横跨多个类的关注点如日志记录、事务管理等模块化的构造。一个切面可以包含多种类型的通知Advice和一个或多个切点Pointcut用于定义在何处以及何时执行这些通知。 连接点Join Point连接点代表程序执行过程中的某个特定位置Spring AOP限定这些位置为方法的调用。简而言之连接点就是能够插入切面通知的点。 通知Advice通知定义了切面在连接点上要执行的动作。根据通知类型的不同这些动作可以在方法调用之前、之后、返回结果后或抛出异常时执行。通知类型包括
前置通知Before advice在方法执行之前执行。后置通知After advice在方法执行后执行无论其结果如何。返回后通知After-returning advice在方法成功执行之后执行。异常后通知After-throwing advice在方法抛出异常后执行。环绕通知Around advice在方法执行之前和之后执行提供对方法调用的全面控制。 切点Pointcut切点是一个表达式切点表达式允许通过方法名称、访问修饰符等条件来匹配连接点决定了通知应该在哪些方法执行时触发。 目标对象Target Object被一个或多个切面所通知的对象。也被称为被代理对象。 AOP代理AOP ProxyAOP框架创建的对象用于实现切面契约由通知和切点定义。在Spring AOP中AOP代理可以是JDK动态代理或CGLIB代理。 引入Introduction引入允许向现有的类添加新的方法或属性。这是通过定义一个或多个附加接口Introduction interfaces实现的AOP框架会为目标对象创建一个代理该代理实现这些接口。
如果还是觉得抽象我们再举一个电影制作的例子来类比 切面Aspect 想象一下有人正在拍摄一部电影而电影中的特效比如爆炸和特殊光效就像是应用程序中需要处理的横切关注点比如日志记录或事务管理。这些特效会在电影的许多不同场景中出现而不仅仅局限于某一个特定场景。在AOP中这些“特效”就是切面它们可以被应用到程序的多个部分而不需要改变实际的场景或代码。 连接点Join Point 继续使用电影的比喻每个场景中的特定时刻比如一个爆炸发生的瞬间可以看作是一个连接点。在编程中这通常对应于方法的调用。 通知Advice 通知就像是导演对特效团队的具体指令比如“在这个场景开始之前加入一个爆炸效果”或“场景结束后显示烟雾渐散的效果”。这些指令告诉特效团队在电影的哪个具体时刻应该添加特定的效果。在AOP中这些“指令”就是通知指定了切面特效应该在连接点特定的代码执行时刻之前、之后或周围执行。 切点Pointcut 如果说通知是导演对特效团队的指令那么切点就是指令中包含的具体条件比如“所有夜晚的外景戏”。切点定义了哪些连接点比如哪些具体的方法调用应该接收通知特效指令。 目标对象Target Object 目标对象就是那些需要添加特效的场景。在我们的编程比喻中它们是那些被切面逻辑影响的对象比如需要日志记录的类。 ️♂️ AOP代理AOP Proxy AOP代理就像是特效团队提供的一个虚拟的、可控制特效的场景副本。这个副本在观众看来与原场景无异但实际上它能在导演需要的时刻自动添加特效。在编程中代理是一个被AOP框架自动创建的对象它包装了目标对象确保了通知特效指令在正确的时间被执行。 引入Introduction 引入就好比是在电影中加入一个全新的角色或者场景这在原本的脚本中并不存在。在AOP中引入允许我们向现有的类添加新的方法或属性这就像是在不改变原始脚本的情况下扩展电影的内容。
2. 通过XML配置实现Spring AOP Spring提供了丰富的AOP支持可以通过XML配置来定义切面、通知advice和切点pointcuts。这样可以在不修改源代码的情况下增加额外的行为如日志、事务管理等
实现步骤 添加Spring依赖在项目的pom.xml中添加Spring框架和AOP相关的依赖。 定义业务接口和实现类创建业务逻辑接口及其实现比如一个简单的服务类。 定义切面类创建一个切面类用于定义前置、后置、环绕等通知。 配置XML在applicationContext.xml中配置切面和业务bean以及AOP相关的标签。
2.1 添加Spring依赖
在pom.xml文件中添加以下依赖
dependenciesdependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.3.10/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-aop/artifactIdversion5.3.10/version/dependencydependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.6/version/dependency
/dependencies2.2 定义业务接口和实现类
首先我们定义一个业务逻辑接口MyService和它的实现MyServiceImpl。
MyService.java:
package com.example.demo.aop;public interface MyService {String performAction(String input) throws Exception;
}MyServiceImpl.java:
package com.example.demo.aop;public class MyServiceImpl implements MyService {Overridepublic String performAction(String action) throws Exception {System.out.println(Performing action in MyService: action);if (throw.equals(action)) {throw new Exception(Exception from MyService);}return Action performed: action;}
}2.3 定义切面类
接下来我们定义一个切面类MyAspect这个类将包含一个前置通知advice它在MyService的performAction方法执行之前执行。
MyAspect.java:
package com.example.demo.aop;import org.aspectj.lang.ProceedingJoinPoint;public class MyAspect {// 前置通知public void beforeAdvice() {System.out.println(Before advice is running!);}// 后置通知public void afterAdvice() {System.out.println(After advice is running!);}// 返回后通知public void afterReturningAdvice(Object retVal) {System.out.println(After returning advice is running! Return value: retVal);}// 异常后通知public void afterThrowingAdvice(Throwable ex) {System.out.println(After throwing advice is running! Exception: ex.getMessage());}// 环绕通知public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println(Around advice: Before method execution);Object result null;try {result joinPoint.proceed();} finally {System.out.println(Around advice: After method execution);}return result;}
}2.4 配置XML
最后我们需要在Spring的配置文件applicationContext.xml中配置上述bean以及AOP的相关内容。
applicationContext.xml:
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd
!--
上面这是XML文件的头部声明它定义了文件的版本和编码类型同时引入了Spring beans 和 AOP 的命名空间。
通过这些命名空间我们可以在XML中使用bean和aop:*标签。
--!-- Bean definitions --bean idmyService classcom.example.demo.aop.MyServiceImpl/bean idmyAspect classcom.example.demo.aop.MyAspect/!-- AOP配置 --aop:config!-- 定义切面及其通知 --aop:aspect idmyAspectRef refmyAspect!-- 定义切点指定通知应该在哪些方法执行时触发 --aop:pointcut idserviceOperation expressionexecution(* com.example.demo.aop.MyService.performAction(..))/!-- 应用前置通知指定方法执行前的操作 --aop:before methodbeforeAdvice pointcut-refserviceOperation/!-- 应用后置通知指定方法执行后的操作不论方法执行成功还是抛出异常 --aop:after methodafterAdvice pointcut-refserviceOperation/!-- 应用返回后通知指定方法成功执行并返回后的操作 --aop:after-returning methodafterReturningAdvice pointcut-refserviceOperation returningretVal/!-- 应用异常后通知指定方法抛出异常后的操作 --aop:after-throwing methodafterThrowingAdvice pointcut-refserviceOperation throwingex/!-- 应用环绕通知提供方法执行前后的完全控制 --aop:around methodaroundAdvice pointcut-refserviceOperation//aop:aspect/aop:config
/beansmyService这是业务逻辑的bean指向MyServiceImpl类的实例。 myAspect这是切面的bean指向MyAspect类的实例。 aop:config这是AOP配置的根元素所有的AOP配置包括切面定义、切点和通知方法等都需要在此元素内部定义。 切面Aspect通过aop:aspect元素定义它包含了一系列通知advice和一个或多个切点pointcut。这个元素将切面类包含通知逻辑的类与具体的操作如何、何时对目标对象进行增强关联起来。 切点Pointcut通过aop:pointcut元素定义切点通过表达式来指定当需要精确控制哪些方法执行时会触发通知时就需要定义切点。切点表达式可以非常精确地指定方法例如通过方法名称、参数类型、注解等。expression定义了切点的表达式指明了切点的匹配规则。这里的表达式execution(* com.example.demo.aop.MyService.performAction(..))意味着切点匹配MyService接口中performAction方法的执行切点用于指定在哪些连接点Join Point例如方法调用上应用通知。
关于解析表达式execution(* com.example.demo.aop.MyService.performAction(..)) execution是最常用的切点函数用于匹配方法执行的连接点。 *表示方法的返回类型是任意的。 com.example.demo.aop.MyService.performAction指定了全路径的接口名和方法名。 (…)表示方法参数是任意的无论方法有多少个参数都匹配。 连接点Join Point连接点是指在程序执行过程中的某一点比如方法的调用。 连接点是通过切点Pointcut的表达式来识别和匹配的execution(* com.example.demo.aop.MyService.performAction(..))表达式定义了一个切点它指定了一个明确的连接点集合——即MyService接口的performAction方法的所有调用。这个例子中MyService接口的performAction方法的调用就是潜在的连接点。每次performAction方法被调用时就达到了一个连接点。这个连接点就是这里通知应用的时机。 通知Advice这是AOP通过在特定时机执行的操作来增强方法的执行。method属性指明当切点匹配时应该执行的切面的方法名pointcut-ref引用了上面定义的切点。比如这里的beforeAdvice是在目标方法performAction执行之前被调用的方法。这意味着每当MyService.performAction(..)方法被调用时beforeAdvice方法将首先被执行。 总结为一句话Spring AOP通过在切面中定义规则切点来指定何时连接点以及如何通知增强特定方法实现代码的模块化和关注点分离无需修改原有业务逻辑。 通过这种方式Spring AOP 允许定义在特定方法执行前、执行后、环绕执行等时机插入自定义逻辑而无需修改原有业务逻辑代码。这是实现关注点分离的一种强大机制特别是对于跨越应用程序多个部分的横切关注点如日志、事务管理等。
注意如果aop:config设置为
aop:config proxy-target-classtrue!-- 其他配置不变 --
/aop:config设置proxy-target-classtrue会使Spring AOP优先使用CGLIB代理即使目标对象实现了接口。默认情况下不需要设置proxy-target-class属性或者将其设置为false则是使用JDK动态代理。
主程序
DemoApplication.java:
package com.example.demo;import com.example.demo.aop.MyService;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class DemoApplication {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);MyService myService (MyService) context.getBean(myService);try {System.out.println(myService.performAction(normal));} catch (Exception e) {e.printStackTrace();}System.out.println();try {System.out.println(myService.performAction(throw));} catch (Exception e) {System.out.println(Exception caught in main: e.getMessage());}context.close();}
}运行结果 通过结合动态代理技术和这些AOP概念Spring AOP能够以非侵入式的方式为应用程序提供横切关注点的支持这样开发者就可以将这些关注点模块化并保持业务逻辑组件的聚焦和简洁。 如果对动态代理感兴趣可以再调试看看这里是JDK动态代理是因为public class MyServiceImpl implements MyService 实现了接口调试如下 简单说一下这里能看到的关键类和接口 ProxyFactory: 这是Spring AOP用来创建代理对象的工厂类。它可以根据目标对象是否实现接口来决定使用JDK动态代理还是CGLIB代理。 AopProxy: 这个接口定义了获取代理对象的方法。它有两个主要实现JdkDynamicAopProxy用于JDK动态代理和CglibAopProxy用于CGLIB代理。 JdkDynamicAopProxy: 实现了AopProxy接口使用JDK动态代理技术创建代理。它实现了InvocationHandler接口拦截对代理对象的所有方法调用。 CglibAopProxy: 同样实现了AopProxy接口但使用CGLIB库来创建代理对象。对于没有实现接口的类Spring会选择这种方式来创建代理。
如果大家想深入了解Spring AOP的源码可以直接查看JdkDynamicAopProxy和CglibAopProxy这两个类的实现。这里不是本篇重点简单提一下
比如在JdkDynamicAopProxy中看到动态代理的实现 JdkDynamicAopProxy类实现了InvocationHandler接口这是JDK动态代理的核心。在其invoke方法中会有逻辑判断是否需要对调用进行拦截并在调用前后应用相应的通知。 创建代理的过程主要是在ProxyFactory通过调用createAopProxy()方法时完成的这个方法会根据配置返回JdkDynamicAopProxy或CglibAopProxy的实例。 代理的使用客户端代码通过ProxyFactory获取代理对象并通过这个代理对象调用目标方法。代理对象在内部使用JdkDynamicAopProxy或CglibAopProxy来拦截这些调用并根据AOP配置执行通知。通过ProxyFactory获取代理对象的过程通常在Spring的配置和使用中是隐式完成的特别是在使用Spring容器管理AOP时。这一过程不需要开发者直接调用ProxyFactory类。当Spring配置中定义了一个bean并对其应用了切面Spring容器会自动处理代理的创建和应用通知的过程。这是通过Spring的后处理器和AOP命名空间的支持实现的开发者通常只需声明式地配置切面和通知即可。
如果想看到CGLIB代理这里有2种方法
第1种方法是去掉MyServiceImpl实现的MyService接口然后把主程序和expression表达式对应的地方改成MyServiceImpl。 第2种方法就是Spring配置文件中显式设置aop:config标签的proxy-target-classtrue属性来实现这一点。如下
aop:config proxy-target-classtrue!-- 其他配置保持不变 --
/aop:config调试如下 欢迎一键三连~ 有问题请留言大家一起探讨学习 ----------------------Talk is cheap, show me the code-----------------------