【JavaEE进阶】 Spring AOP源码简单剖析

简介: 【JavaEE进阶】 Spring AOP源码简单剖析

🍃前言

前面的博客中,博主对代理模式进行了一个简单的讲解,接下来博主将对Spring AOP源码进行简单剖析,使我们对Spring AOP了解的更加深刻。

🍀Spring AOP源码剖析

Spring AOP 主要基于两种⽅式实现的:JDK 及 CGLIB 的⽅式

Spring对于AOP的实现,基本上都是靠AnnotationAwareAspectJAutoProxyCreator 去完成⽣成代理对象的逻辑在⽗类 AbstractAutoProxyCreator 中

相关源码与注解如下:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                             @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)
                this.beanFactory, beanName, beanClass);
    }
//创建代理⼯⼚
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);
/**
 * 检查proxyTargetClass属性值,spring默认为false
 * proxyTargetClass 检查接⼝是否对类代理, ⽽不是对接⼝代理
 * 如果代理对象为类, 设置为true, 使⽤cglib代理
 */
    if (!proxyFactory.isProxyTargetClass()) {
//是否有设置cglib代理
        if (shouldProxyTargetClass(beanClass, beanName)) {
//设置proxyTargetClass为true,使⽤cglib代理
            proxyFactory.setProxyTargetClass(true);
        } else {
/**
 * 如果beanClass实现了接⼝,且接⼝⾄少有⼀个⾃定义⽅法,则使⽤JDK代理
 * 否则CGLIB代理(设置ProxyTargetClass为true )
 * 即使我们配置了proxyTargetClass=false, 经过这⾥的⼀些判断还是可能会将其
 设为true
 */
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
// Use original ClassLoader if bean class not locally loaded in overriding
    class loader
ClassLoader classLoader = getProxyClassLoader();
    if (classLoader instanceof SmartClassLoader && classLoader !=
            beanClass.getClassLoader()) {
        classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
    }
//从代理⼯⼚中获取代理
    return proxyFactory.getProxy(classLoader);
}

代理工⼚有⼀个重要的属性:proxyTargetClass,默认值为false.

也可以通过程序设置

proxyTargetClass ⽬标对象 代理⽅式
false 实现了接⼝ jdk代理
false 未实现接⼝(只有实现类) cglib代理
true 实现了接⼝ cglib代理
true 未实现接⼝(只有实现类) cglib代理

可以通过 @EnableAspectJAutoProxy(proxyTargetClass = true) 来设置

需要注意的是:

  • Spring Boot 2.X开始,默认使⽤CGLIB代理,可以通过配置项 spring.aop.proxy-target-class=false 来进⾏修改,设置默认为jdk代理
    SpringBoot设置 @EnableAspectJAutoProxy ⽆效,因为Spring Boot默认使⽤AopAutoConfiguration进⾏装配
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context =
                SpringApplication.run(DemoApplication.class, args);
/**
 * HouseProxy houseProxy = context.getBean(HouseProxy.class);
 * 设置spring.aop.proxy-target-class=true cglib代理, 运⾏成功
 * 设置spring.aop.proxy-target-class=false jdk代理, 运⾏失败, 不能代理类
 * 因为 HouseProxy 是⼀个类, ⽽不是接⼝, 需要修改为
 * HouseSubject houseProxy = (HouseSubject)
 context.getBean("realHouseSubject")
 *
 */
        HouseProxy houseProxy = context.getBean(HouseProxy.class);
//HouseSubject houseProxy = (HouseSubject)
        context.getBean("realHouseSubject");//正确运⾏
        System.out.println(houseProxy.getClass().toString());
    }
}

注意:使⽤context.getBean()需要添加注解,使HouseProxy,RealHouseSubject被Spring管理测试AOP代理,需要把这些类交给AOP管理(⾃定义注解或使用@Aspect)

我们再看以下代理⼯⼚的代码

public class ProxyFactory extends ProxyCreatorSupport {
    //...代码省略
//获取代理
    public Object getProxy(@Nullable ClassLoader classLoader) {
//分两步 先createAopProxy,后getProxy
        return createAopProxy().getProxy(classLoader);
    }
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
//...代码省略
}

createAopProxy的实现在DefaultAopProxyFactory中

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    //...代码省略
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws
            AopConfigException {
/**
 * 根据proxyTargetClass判断
 * 如果⽬标类是接⼝, 使⽤JDK动态代理
 * 否则使⽤cglib动态代理
 */
        if (!NativeDetector.inNativeImage() &&
                (config.isOptimize() || config.isProxyTargetClass() ||
                        hasNoUserSuppliedProxyInterfaces(config))) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine
                        target class: " +
                "Either an interface or a target is required for proxy
                creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) ||
                    ClassUtils.isLambdaClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
//...代码省略
}

接下来就是创建代理了

JDK动态代理

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler,
        Serializable {
    //...代码省略
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " +
                    this.advised.getTargetSource());
        }
        return Proxy.newProxyInstance(determineClassLoader(classLoader),
                this.proxiedInterfaces, this);
    }
//...代码省略
}

CGLIB动态代理

class CglibAopProxy implements AopProxy, Serializable {
    //...代码省略
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        //...代码省略
// Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
// Generate the proxy class and create a proxy instance.
        return createProxyClassAndInstance(enhancer, callbacks);
    }
//...代码省略
}

以上就是对Spring AOP源码的一个简单剖析。

⭕总结

关于《【JavaEE进阶】 Spring AOP源码简单剖析》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下

相关文章
|
5天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
18 2
|
22天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
11天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
11天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
37 9
|
1月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
37 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
16天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
12天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
25 0
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
111 5
|
1月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
69 2