三种代理实现
1 JDK动态代理实现-基于接口代理
2 CGLIB动态代理实现-基于类代理
3 AspectJ 适配实现
为什么Proxy.newProxyInstance 会生成新的字节码?
创建代理类:
Proxy.newProxyInstance 首先会检查缓存中是否有已存在的代理类字节码。
如果没有,则会生成一个新的字节码文件,并将其加载到 JVM 中。
字节码生成过程:
类定义:生成一个新的类,这个类实现了传入的所有接口。
方法重写:对于每个接口的方法,代理类都会生成一个方法实现,这些方法内部会调用 InvocationHandler.invoke 方法。
方法调用:当代理对象的方法被调用时,实际上会调用 InvocationHandler.invoke 方法,从而实现方法的拦截和增强。
为什么Java动态代理无法满足AOP的需要?
接口限制:Java动态代理要求目标对象必须实现一个或多个接口。如果目标对象是一个具体的类,并且没有实现任何接口,那么就无法直接使用Java动态代理。在这种情况下,需要使用其他技术,如CGLIB,它可以为目标类创建子类来实现动态代理。
为什么Spring推荐AspectJ注解?
- 更简洁的代码
减少配置:使用 AspectJ 注解可以减少 XML 配置文件中的配置量,使得代码更加简洁易读。传统的 Spring AOP 需要在 XML 文件中配置大量的 aop:config 和 aop:pointcut 元素,而使用 AspectJ 注解可以直接在 Java 类中声明切面、切入点和通知。 - 更强大的切入点表达式
丰富的表达式:AspectJ 提供了比 Spring AOP 更强大的切入点表达式语言,支持更复杂的匹配规则,比如基于方法签名、类层次结构、异常等条件的匹配。这对于实现更细粒度的控制是非常有用的。 - 编译期织入
编译期织入:AspectJ 支持编译期织入(Compile-time Weaving),这意味着可以在编译阶段就将切面代码织入到目标类中。这样做的好处是可以提高运行时的性能,因为切面逻辑已经内联到了业务代码中,减少了运行时的代理调用开销。
类装载期织入:此外,AspectJ 还支持类装载期织入(Classloading-time Weaving),可以在应用程序启动时进行织入操作,这也是一种较为灵活的方式。 - 更好的可维护性和可扩展性
分离关注点:使用 AspectJ 注解可以更好地实现关注点的分离,将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,集中在一个地方进行管理和维护。
易于扩展:由于 AspectJ 注解直接在 Java 类中声明,因此更容易扩展和复用切面逻辑。 - 社区支持和技术成熟度
广泛支持:AspectJ 是一个成熟的 AOP 框架,拥有广泛的社区支持和丰富的文档资源。Spring 采用与 AspectJ 相同的注解风格,使得开发者可以利用 AspectJ 的强大功能,同时也保持了与 Spring 生态系统的良好集成。 - 无缝集成
Spring 集成:Spring 与 AspectJ 的集成非常紧密,Spring 不仅支持 AspectJ 的注解,还提供了与 Spring 容器的良好集成,使得开发者可以方便地在 Spring 应用中使用 AspectJ 的功能。