美文网首页spring frameworkspringJava 程序员
源码分析:Spring是如何实现AOP的?

源码分析:Spring是如何实现AOP的?

作者: 马小莫QAQ | 来源:发表于2021-11-22 16:28 被阅读0次

    什么是AOP

    AOP(Aspect Oriented Programming),即面向切面编程,是Spring框架中的一个核心内容,主要目的是对业务逻辑进行隔离,让业务代码更加关注于实现功能,降低耦合度

    举个例子,AOP的典型使用场景就是日志和安全,比如我们要记录一段代码的执行时间,很容易想到的方法就是在执行的开始处打印一个时间,在执行的结尾处再打印一个时间,两个时间相减就是代码真正的执行时间。

    但这样会有一个问题,就是假如我有很多这样的方法需要统计执行时间,难道我每一个方法都要去加这个时间打印吗?

    AOP可以解决这样的问题,它通过配置的方式可以实现对类的增强,在不改动原有方法的基础上进行功能的增强

    这样的话,不管有多少个地方需要统计执行时间,我们都可以轻松的实现,下面来看一下AOP的原理

    Spring AOP的原理

    Spring AOP的实现原理是Java的动态代理

    动态代理,说的是在程序运行期间动态的为目标类创建一个代理类,从而实现为目标类额外添加一些功能的目的

    下面用一张图来说明一下

    请原谅我的画图技术 ^ _ ^

    • 从IOC容器中获取普通对象时,容器会创建一个对象的实例并返回
    • 从IOC容器中获取一个需要被增强的对象时,会创建两个对象:代理对象、目标对象,我们实际调用的是代理对象,由代理对象再调用目标对象

    想想为啥会多出一个代理对象?

    上面提到AOP的指职是要实现在类上增加一些额外的功能,那么在不修改目标类的情况下,就会生成一个代理类,这个代理类相当于对目标类进行了一层包装,它包含目标类的所有功能并且还额外的新增了一些功能点

    反正原理就是这么个原理~~~

    AOP中几个重要的概念

    在介绍这些概念之前,我们先想一个问题,假如让你来设计AOP,你应该怎么实现?

    首先,我们知道AOP的主要用途是在不改变目标类的情况下,对目标类添加一些额外的功能进行增强,主要原理是使用动态代理来动态的生成代理对象,在代理对象中添加额外的功能

    那么,我们要生成代理对象,肯定需要搞清楚几个问题

    • 我需要对谁生成代理对象(目标对象)
    • 哪些地方可以让我来添加额外的功能(连接点)
    • 实际我需要添加额外功能的点(切点)
    • 我需要在目标对象执行之前或之后来添加额外的功能(增强)

    以上问题可以表述为AOP里面几个重要的概念

    • Joint point(连接点),表示程序中明确定义的点,比如方法调用、成员访问、异常处理这些点都是AOP可以织入的点
    • Pointcut(切点),表示AOP具体需要织入的点,也就是从Joint point(连接点)中过滤出来的一些点
    • Advice(增强),表示我要对需要强入的点做什么操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码
    • Target(目标对象),需要增强的具体对象
    • Weaving(织入),将额外的功能添加到目标对象的过程
    • Aspect(切面),PointCut和Advice的组合

    Advice类型:

    • before advice 在 join point 前被执行的 advice
    • after return advice 在join point 正常返回后执行的 advice
    • after throwing advice 当一个 join point 抛出异常后执行的 advice
    • after(final) advice 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
    • around advice 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice
    • introduction 可以为原有的对象增加新的属性和方法

    理解了这些概念,才能对AOP有全面的认识

    看个例子吧

    1、定义两个接口

    public interface UserService {
        public void login();
    }
    
    public interface OrderService {
        public void commitOrder();
    }
    
    

    2、实现

    @Component
    public class AppUserService implements UserService {
        @Override
        public void login() {
            System.out.println("APP用户登录");
        }
    }
    
    @Component
    public class AppOrderService implements OrderService {
        @Override
        public void commitOrder() {
            System.out.println("App提交订单");
        }
    }
    
    @Component
    public class WechatUserService {
        public void login() {
            System.out.println("微信用户登录");
        }
    }
    
    

    3、定义切面

    @Aspect
    @Component
    public class UserAspectJ {
        @Before("execution(* org.kxg.springDemo.aop.UserService.login(..)) || execution(* org.kxg.springDemo.aop.WechatUserService.login(..))")
        public void mark(){
            System.out.println("登录之前记录一下时间");
        }
    }
    
    

    从这里可以看出来,我们对接口和普通类都做了增强处理

    4、使用自动配置的加载类

    @Configuration
    @ComponentScan(basePackages = "org.kxg.springDemo.aop")
    @EnableAspectJAutoProxy
    public class AppConfig {
    
    }
    
    

    5、测试一下

    public class AopMain {
        public static void main(String[] args){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            UserService appUserService = context.getBean("appUserService",UserService.class);
            WechatUserService wechatUserService = context.getBean("wechatUserService",WechatUserService.class);
            OrderService orderService = context.getBean("appOrderService",OrderService.class);
            appUserService.login();
            wechatUserService.login();
            orderService.commitOrder();
        }
    }
    
    

    运行结果:

    登录之前记录一下时间
    APP用户登录
    登录之前记录一下时间
    微信用户登录
    App提交订单
    

    可以看出来,在执行APP用户登录和微信用户登录之前,执行了我们切面中的mark方法,因为我们定义的是前置通知(@Before),会在目标方法之前执行

    下面我们通过源码的角度来看一下Spirng AOP是如何实现的

    Spring AOP是如何实现的

    我们都知道AOP的实现方法是动态代理,就是在程序运行期间动态的为目标类创建代理,从而实现目标类的增强

    Java的动态代理有两种实现方式:

    • JDK的动态代理
    • CGlib动态代理

    这两种动态代理的主要区别:

    • JDK是通过代理类跟目标类实现同一个接口来实现代理的
    • CGlib是通过继承目标类来实现代理的

    一个是实现接口,一个是类继承

    从上面的例子可以看出来,Spring对于接口和普通类都可以实现AOP增强,那Spring在实现AOP的时候到底是用的JDK动态代理,还是CGlib动态代理呢?

    官方给出的解释是,对实现了接口的类进行增强时使用JDK的动态代理,普通类的增强使用CGlib

    下面我们来看一下是不是如官方所说

    AppUserService是实现了接口的类,使用的是JDK动态代理

    WechatUserService是个普通类,使用的是CBLIB动态代理

    既然CGLIB可以实现普通类的增强,那它必然也是支持实现了接口的类的增强,因为实现了接口的类也是普通类

    我们只要修改一个参数,就可以实现全部使用CGLIB动态代理

    @Configuration
    @ComponentScan(basePackages = "org.kxg.springDemo.aop")
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class AppConfig {
    
    }
    
    

    proxyTargetClass = true 表示所有类都使用CGLIB动态代理,我们修改参数后,运行结果如下图所示

    可以看出来,AppUserService是实现了接口的类,默认情况下是使用JDK动态代理,当把@EnableAspectJAutoProxy注解的proxyTargetClass属性改为true时,所有类都使用CBLIB动态代理

    下面我们来具体跟一下代码,看看Spring是如何实现AOP的

    首先我们还是从入口处开始

    public class AopMain {
        public static void main(String[] args){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            UserService appUserService = context.getBean("appUserService",UserService.class);
            WechatUserService wechatUserService = context.getBean("wechatUserService",WechatUserService.class);
            OrderService orderService = context.getBean("appOrderService",OrderService.class);
            appUserService.login();
            wechatUserService.login();
            orderService.commitOrder();
        }
    }
    
    

    当从Spring IOC容器中获取对象时,假如对象需要进行AOP增强,就会生成代理对象,所以我们从getBean方法入手,getBean就是从容器中获取对象

    从Spring容器中获取对象的过程,这里就不再详细展开了,我们只看主要的方法

    //AbstractAutowireCapableBeanFactory(类名)
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
    
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            }
    
            try {
                invokeInitMethods(beanName, wrappedBean, mbd);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(
                        (mbd != null ? mbd.getResourceDescription() : null),
                        beanName, "Invocation of init method failed", ex);
            }
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
    
            return wrappedBean;
        }
    
    

    从方法名就可以看出来,initializeBean方法主要是用来做Bean初始化的,在初始化之后有一个后处理的方法
    applyBeanPostProcessorsAfterInitialization

    这个方法就是用来处理动态代理的

    //AbstractAutowireCapableBeanFactory(类名)
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor processor : getBeanPostProcessors()) {
                Object current = processor.postProcessAfterInitialization(result, beanName);
                if (current == null) {
                    return result;
                }
                result = current;
            }
            return result;
        }
    
    
    //AbstractAutoProxyCreator(类名)
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    
    
    //AbstractAutoProxyCreator(类名)
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
                return bean;
            }
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
    
           //注意看这里的注释:这里就是创建代理对象的地方,如果有AOP的advice就创建代理对象
            // Create proxy if we have advice.
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                //这里进行代理对象的创建
                Object proxy = createProxy(
                        bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
    
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    
    
    //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);
    
            if (!proxyFactory.isProxyTargetClass()) {
                if (shouldProxyTargetClass(beanClass, beanName)) {
                    proxyFactory.setProxyTargetClass(true);
                }
                else {
                    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);
            }
    
            return proxyFactory.getProxy(getProxyClassLoader());
        }
    
    
    public Object getProxy(@Nullable ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }
    
    

    这里可以看到,获取代理对象的具体实现有两种,分别对应的是JDK的动态代理和CGLIB的动态代理

    //JdkDynamicAopProxy(类名)
    public Object getProxy(@Nullable ClassLoader classLoader) {
            if (logger.isTraceEnabled()) {
                logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
            }
            Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            //JDK动态代理创建代理对象
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    
    
    //CglibAopProxy(类名)
    public Object getProxy(@Nullable ClassLoader classLoader) {
            if (logger.isTraceEnabled()) {
                logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
            }
    
            try {
                Class<?> rootClass = this.advised.getTargetClass();
                Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
    
                Class<?> proxySuperClass = rootClass;
                if (ClassUtils.isCglibProxyClass(rootClass)) {
                    proxySuperClass = rootClass.getSuperclass();
                    Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                    for (Class<?> additionalInterface : additionalInterfaces) {
                        this.advised.addInterface(additionalInterface);
                    }
                }
    
                // Validate the class, writing log messages as necessary.
                validateClassIfNecessary(proxySuperClass, classLoader);
    
                // Configure CGLIB Enhancer...
                Enhancer enhancer = createEnhancer();
                if (classLoader != null) {
                    enhancer.setClassLoader(classLoader);
                    if (classLoader instanceof SmartClassLoader &&
                            ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                        enhancer.setUseCache(false);
                    }
                }
                enhancer.setSuperclass(proxySuperClass);
                enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
                enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
                enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
    
                Callback[] callbacks = getCallbacks(rootClass);
                Class<?>[] types = new Class<?>[callbacks.length];
                for (int x = 0; x < types.length; x++) {
                    types[x] = callbacks[x].getClass();
                }
                // fixedInterceptorMap only populated at this point, after getCallbacks call above
                enhancer.setCallbackFilter(new ProxyCallbackFilter(
                        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
                enhancer.setCallbackTypes(types);
    
                // Generate the proxy class and create a proxy instance.
                return createProxyClassAndInstance(enhancer, callbacks);
            }
            catch (CodeGenerationException | IllegalArgumentException ex) {
                throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
                        ": Common causes of this problem include using a final class or a non-visible class",
                        ex);
            }
            catch (Throwable ex) {
                // TargetSource.getTarget() failed
                throw new AopConfigException("Unexpected AOP exception", ex);
            }
        }
    
    
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
            enhancer.setInterceptDuringConstruction(false);
            enhancer.setCallbacks(callbacks);
            //CGLIB创建代理对象实例
            return (this.constructorArgs != null && this.constructorArgTypes != null ?
                    enhancer.create(this.constructorArgTypes, this.constructorArgs) :
                    enhancer.create());
        }
    
    

    至此两种类型的动态代理对象都创建好了,从Spring容器中获取对象时,返回的就是代理的对象,我们在代理对象中额外添加的功能也就可以生效了

    现在来整体梳理一下整个SpringAop的具体流程

    • Spirng会把类装载到IOC容器中
    • 当需要创建对象时,会直接从IOC容器中获取
    • 从IOC容器中获取对象时,发现对象需要进行增强时就会生成代理对象,将增强部分生成到代理类中
    • 实际业务中调用的是增强后的代理对象,由代理对象再去调用目标对象,代理对象相当于做了一层包装

    总结一下

    • AOP是Spring框架中的一个核心内容,主要目的是对业务逻辑进行隔离,让业务代码更加关注于实现功能,降低耦合度
    • Spring AOP的实现原理是Java的动态代理
    • Java的动态代理有两种实现方式
    • JDK动态代理
    • CGLIB动态代理
    • AOP中几个重要的概念
    • Joint point(连接点),表示程序中明确定义的点,比如方法调用、成员访问、异常处理这些点都是AOP可以织入的点
    • Pointcut(切点),表示AOP具体需要织入的点,也就是从Joint point(连接点)中过滤出来的一些点
    • Advice(增强),表示我要对需要强入的点做什么操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码
    • Target(目标对象),需要增强的具体对象
    • Weaving(织入),将额外的功能添加到目标对象的过程
    • Aspect(切面),PointCut和Advice的组合
    • Spring对于实现了接口的类默认情况下是使用JDK动态代理生成代理对象,对没有实现接口的类使用CGLIB动态代理生成代理对象,当然你也可以修改配置来让所有的情况都通过CGLIB动态代理来生成代理对象
    • SpringAOP的具体实现流程
    • Spirng会把类装载到IOC容器中
    • 当需要创建对象时,会直接从IOC容器中获取
    • 从IOC容器中获取对象时,发现对象需要进行增强时就会生成代理对象,将增强部分生成到代理类中
    • 实际业务中调用的是增强后的代理对象,由代理对象再去调用目标对象,代理对象相当于做了一层包装

    作者:果子爸聊技术
    原文链接:https://blog.csdn.net/pzjtian/article/details/110354827

    相关文章

      网友评论

        本文标题:源码分析:Spring是如何实现AOP的?

        本文链接:https://www.haomeiwen.com/subject/aiybtrtx.html