Spring 5.x 源码解析之详解AOP原理之生成代理

Spring 5.x 源码解析之详解AOP原理之生成代理

AOP代理是怎么生成

前面那篇只是对AOP做了简单的理解,希望能明白AOP具体做了什么,大致的原理是什么,本篇才是解释spring aop是怎么做到的,希望通过源码的方式来讲述整个过程,当然也是通过一个简单的例子啦。首先就先看看我们的简单例子的结构:
在这里插入图片描述
我们需要一个配置类AopConfig,里面有一个服务,一个切面:

package com.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

package com.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.aop")
public class AopConfig {
	public AopConfig(){
		System.out.println("------AopConfig--------");
	}

	@Bean
	public ServiceInterface getService(){
		return new Service();
	}

	@Bean
	public LogAspects logAspects(){
		return new LogAspects();
	}
}


我们的服务很简单Service

package com.aop;

public class Service {
	public Service(){
		System.out.println("=======Service=======");
	}

	//业务方法
	public int doService(int i) {
		int result=5/i;
		System.out.println("运行doService");
		return result;
	}
}

我们的切面是对服务打log:

package com.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

/*
 * log切面类
 * 通知:
 * 前置 方法调用前@Before
 * 后置 方法调用后@After
 * 返回 方法返回后运行@AfterReturning
 * 异常 方法出异常后@AfterThrowing
 */
@Aspect
public class LogAspects {

	public LogAspects() {
		System.out.println("======LogAspects========");
	}

	@Pointcut("execution(* com.aop.Service.*(..))")
	public void pointCut() {
	}

	/**
	 * 在目标方法执行前
	 */
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint) {
		System.out.println("logStart  开始运行:" + joinPoint.getSignature().getName());
	}

	/**
	 * 在目标方法执行后
	 */
	@After("pointCut()")
	public void logAfter() {
		System.out.println("logAfter  结束运行");
	}

	/**
	 * 方法返回后
	 */
	@AfterReturning(value = "pointCut()", returning = "result")
	public void logReturning(Object result) {
		System.out.println("logReturning  正常返回,结果:" + result);
	}

	/**
	 * 出现异常后
	 */
	@AfterThrowing(value = "pointCut()", throwing = "exception")
	public void logException(Exception exception) {
		System.out.println("logStarException  运行异常:" + exception);
	}



}


最后是我们的测试类:

package com.aop;


import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AopTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
		Service service = applicationContext.getBean(Service.class);
		System.out.println(service.doService(1));

	}
}

代码先放着,我们先来说说执行的流程,先给一张主要的刷新流程图:

//刷新前预处理
			// Prepare this context for refreshing.
			prepareRefresh();

			// 获取BeanFactory
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// BeanFactory预准备,属性赋值
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// 自定义的子类实现
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// 执行BeanFactoryPostProcessors方法
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册后置处理器
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// 标签国际化
				// Initialize message source for this context.
				initMessageSource();

				// 初始化事件通知
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// 自定义的刷新
				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// 单例bean的实例化,不包括延迟加载
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

首先我们知道很多的操作都是由后置处理器来完成的,因为声明了@EnableAspectJAutoProxy
而这个注解类引入了AspectJAutoProxyRegistrar,而且实现了ImportBeanDefinitionRegistrar接口,就是在以后埋下的伏笔,才能有AspectJAwareAdvisorAutoProxyCreator的定义:
在这里插入图片描述
在这里插入图片描述
然后在调用invokeBeanFactoryPostProcessors(beanFactory)的时候,会进入调用ImportBeanDefinitionRegistrar接口,从而进入AspectJAutoProxyRegistrar调用registerBeanDefinitions:
在这里插入图片描述
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);会定义AspectJAwareAdvisorAutoProxyCreator在这里插入图片描述
然后我们就可以看到有那么多的Bean定义了,当然前面那步也或把Java配置类的@Bean的工厂方法也定义进来:
在这里插入图片描述
但是还没有创建出来:
在这里插入图片描述

然后在继续往下走,registerBeanPostProcessors(beanFactory);里会进行后置处理器的实例化,具体就不跟进去了:
在这里插入图片描述
然后继续走,一直走到finishBeanFactoryInitialization(beanFactory);这里才是单例Bean的实例化的地方。我们拿前面定义的Service类来讲,看他怎么实例化的,其实就是遍历我们的Bean定义,然后发现有工厂方法getService,然后用反射去执行实例化,当然这之前肯定是先把配置类给实例化的:
在这里插入图片描述
可以看到,这个工厂方法调用其实是CGlib的代理对象。这个时候实例还是Service,马上要进行初始化后置处理了,这个里面才会将他包装成代理对象:
在这里插入图片描述

就是AnnotationAwareAspectJAutoProxyCreator这个后置处理器做的事:
在这里插入图片描述
在这里插入图片描述
最终我们的实例对象只是被当做代理工厂的目标源了:
在这里插入图片描述
会创建aop代理,然后获得代理:
在这里插入图片描述
里面就是创建JDK的还是CGLib的aop代理:
在这里插入图片描述
如果是JDK的话就调用,这个应该很熟悉吧:
在这里插入图片描述
否则就是CGLib,要做一大堆事,设置代理类,设置拦截器,设置通知方法等:

@Override
	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 (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				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 ClassLoaderAwareGeneratorStrategy(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);
		}
	}

最后发现生成的已经不是Service了,是CGLib的代理对象:
在这里插入图片描述
可以和前面对照:
在这里插入图片描述
这样我们的代理对象就有了,那我们的那些拦截器通知方法哪里来呢,其实也是finishBeanFactoryInitialization(beanFactory);中的。在Java配置类的实例化之前,会有后置处理器AnnotationAwareAspectJAutoProxyCreator处理,会去遍历所有的Bean名字定义,找出是切面的类,然后将里面的通知实例化后放缓存里:
在这里插入图片描述
其实很多地方细节都没讲到,因为不太好说,方法多,跳跃也多,讲了一些主要的地方,具体还是得自己去看比较好,我这里总结了个大致的图:
在这里插入图片描述
下一篇再来讲讲调用的时候是怎么进行的。好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值