AOP的基础知识总结(jdk动态代理cglib动态代理)

xiaoxiao2025-04-11  8

AOP的基础知识总结(jdk动态代理/cglib动态代理)

知识总结

aop切面编程

切面:

切面包含了通知和切点,通知和切点共同定义了切面是什么,在何时,何处执行切面逻辑。

切点:

如果说通知定义了在何时执行通知,那么切点就定义了在何处执行通知。所以切点的作用就是 通过匹配规则查找合适的连接点(Joinpoint),AOP 会在这些连接点上织入通知。

通知:

Spring 中对应了 5 种不同类型的通知: · 前置通知(Before):在目标方法执行前,执行通知 · 后置通知(After):在目标方法执行后,执行通知,此时不关系目标方法返回的结果是什么 · 返回通知(After-returning):在目标方法执行后,执行通知 · 异常通知(After-throwing):在目标方法抛出异常后执行通知 · 环绕通知(Around): 目标方法被通知包裹,通知在目标方法执行前和执行后都被会调用

动态代理:

Spring在选择用JDK还是CGLiB的依据:

(1)当Bean实现接口时,Spring就会用JDK的动态代理(就比如userServiceImpl实现了IUserService) (2)当Bean没有实现接口时,Spring使用CGlib是实现(就比如userServiceImpl没有实现IUserService) (3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

CGlib比JDK快?

(1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。 (2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

JDK动态代理和CGLIB字节码生成的区别?

(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类 (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 因为是继承,所以该类或方法最好不要声明成final

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

Spring的aop的基本的使用:

增加依赖包:

jdk:不需要额外添加依赖 cglib: org.springframework.spring-aop.5.0.8.RELEASE org.aspectj.aspectjweaver.1.8.13 org.springframework.spring-aspects.5.0.8.RELEASE aopalliance.aopalliance.1.0

增加切面类类:

① 在类上使用 @Component 注解 把切面类加入到IOC容器中 ② 在类上使用 @Aspect 注解 使之成为切面类

案例(可以只使用环绕通知/其他的前置后置通知之一):

@Component @Aspect public class LoggingAspect { /** * 前置通知:目标方法执行之前执行以下方法体的内容 * @param jp */ @Before("execution(* com.qcc.beans.aop.*.*(..))") public void beforeMethod(JoinPoint jp){ String methodName = jp.getSignature().getName(); System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs())); } /** * 返回通知:目标方法正常执行完毕时执行以下代码 * @param jp * @param result */ @AfterReturning(value="execution(* com.qcc.beans.aop.*.*(..))",returning="result") public void afterReturningMethod(JoinPoint jp, Object result){ String methodName = jp.getSignature().getName(); System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】"); } /** * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。 * @param jp */ @After("execution(* com.qcc.beans.aop.*.*(..))") public void afterMethod(JoinPoint jp){ System.out.println("【后置通知】this is a afterMethod advice..."); } /** * 异常通知:目标方法发生异常的时候执行以下代码 */ @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e") public void afterThorwingMethod(JoinPoint jp, NullPointerException e){ String methodName = jp.getSignature().getName(); System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e); } // /** // * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码 // * @return // */ // @Around(value="execution(* com.qcc.beans.aop.*.*(..))") // public Object aroundMethod(ProceedingJoinPoint jp){ // String methodName = jp.getSignature().getName(); // Object result = null; // try { // System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs())); // //执行目标方法 // result = jp.proceed(); // System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result); // } catch (Throwable e) { // System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e); // } // // System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------"); // return result; // } }
转载请注明原文地址: https://www.6miu.com/read-5028038.html

最新回复(0)