上篇文章主要有以下几个主题:
- 围绕SpringBoot AOP加载原理。
- Spring AOP 是嵌入在Spring 容器启动哪个阶段。
- 不进行增强的原理,其中包含寻找增强器(Advisor)逻辑。
本文将围绕 创建代理过程 进行更近一步研究。
postProcessAfterInitialization
还是从Spring 容器处理器固定方法开始,AbstractAutoProxyCreator
定义的 postProcessAfterInitialization
,当每个bean初始化完,都会执行这个方法:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取缓存的key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
上面方法,简单获取完用于缓存的key后,就进入到 wrapIfNecessary
方法进行具体包装:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经是 targetSourceBean了,即为增强器,那么就不进行代理,直接返回
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 不在advisedBeans 中
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;
}
// 获取所有过滤器
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;
}
上面方法除了普通检查外,需要对两行代码具体分析。
获取所有过滤器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
和
// 创建代理过程
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
getAdvicesAndAdvisorsForBean
看这个方法具体内容:
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors :
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 是否设置在头结点设置 ExposeInvocationInterceptor 类型切点拦截器advisor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
对于bean的增强,肯定有两个方面:
- 获取所有的增强器这在
findCandidateAdvisors
体现。 - 利用第一步中找到的增强器,找到该bean适用的增强器,在
findAdvisorThatCanApply
。
findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
这个方法在上一篇文章中有详细介绍,总结如下:
- 加载xml中配置接口,或者继承
Advisor
类的 配置接口。 - 使用
BeanFactoryAspectJAdvisorsBuilder
去搜寻使用@Aspectj
注解类,并构建的Advisor
findAdvisorsThatCanApply
上一步中,完成了所有增强器的解析,但是并不是所有都适用于当前bean,所以需要进一步过滤:
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 设置当前正在装配的beanName
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 筛选出合适的Advisor
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
findAdvisorsThatCanApply:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 处理 IntroductionAdvisor 类型增强器
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 对于普通bean处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
如何才能确定,这个bean的这些方法需要增强呢?看canApply方法:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
// IntroductionAdvisor 类型advisor
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
// 切点增强器advisor
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
默认返回true
return true;
}
}
即使用每个注解上面配置的 PointCut 注解进行匹配,匹配完后即 加入到 eligibleAdvisors
中。
createProxy
搜寻完,过滤完,即开始进入创建代理过程,入口方法为 createProxy
。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 设置该bean的 originalTargetClass 属性
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 定义代理工厂类
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 设置代理规则,使用jdk还是cglib
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 将上一步获取的过滤后的specificInterceptors ,转化为advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 增加 advisor增强器
proxyFactory.addAdvisors(advisors);
// 设置targetSource
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 设置freezen属性,默认为false,即代理配置后,不允许修改代理值。
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成并获取操作。
return proxyFactory.getProxy(getProxyClassLoader());
}
上面即是创建代理过程,Spring将其委托给ProxyFactory处理,这里主要是对ProxyFactory进行初始化工作。
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
中间有一部创建Aop代理工厂过程:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
看DefaultAopProxyFactory
的createAopProxy
方法:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
上面方法主要是判断使用何种代理:
是否 设置优化optimize,或者设置proxyTargetClass或者代理类没有接口,将影响Spring使用代理方式。
- 如果目标对象,实现了接口,默认情况采用jdk动态代理。
- 如果目标对象实现接口,可以强制使用CGLIB实现AOP。
- 如果没有实现接口,那么必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间切换。
JDK和CGLIB字节码区别:
- JDK动态代理只能对实现接口的类生成代理,而不针对类。
- CGLIB是针对类,实现方式为对类生成一个子类,覆盖其中方法,因为是集成,所以无法集成final方法或者类。
具体JDK和CGLIB例子可以看博主文章:
- jdk: https://blog.csdn.net/anLA_/article/details/77074557
- cglib:https://blog.csdn.net/anLA_/article/details/77074955
JdkDynamicAopProxy
对于JDK代理,有以下几个点:
- 继承
InvocationHandler
- 将代理对象传入,通过构造方法,或者普通方法。
- 重写
invoke
方法 getProxy
方法,获取代理后的对象
既然创建的是代理,并且后文还会执行代理类的getProxy
,所以直接看具体方法:
@Override
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);
// 配置equals和hashCode接口
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 生成代理
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
在 completeProxiedInterfaces
中,主要是添加 SpringProxy
、Advised
、DecoratingProxy
三种类型接口以及当前bean自身实现的接口bean。
代理生成完毕,接下来看 invoke
方法中内容:
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 用于保留旧对象
Object oldProxy = null;
boolean setProxyContext = false;
// 获取targetSource
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// equals方法,直接执行
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// hashcode方法,直接执行
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
// 如果是 执行 DecoratingProxy 的几个方法,那么直接执行
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
// 如果执行 Advised 的方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 用于处理,目标对象自我调用命中切面,需要使用此属性来暴露。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 获取当前对象即其类型
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取当前方法的执行链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// 如果没有要执行的切面,则直接执行
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 由前面的执行链路,创建一个MethodInvocation执行。
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 具体执行方法
retVal = invocation.proceed();
}
// 如果有返回值,则获取类型并返回
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 设置为原始的代理执行对象
AopContext.setCurrentProxy(oldProxy);
}
}
}
除了最开始几个if对方法类型及参数判断,主要逻辑还是在过滤器链逻辑组装处。
AOP过滤器链
对上面部分代码选出来分析:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
JdkDynamicAopProxy
中 advised
为构造方法创建时传入,就是上面构造的 ProxyFactory
对象。
获取过滤器链操作:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
从advisorChainFactory
中获取过滤器链,主要过程就是讲该方法去和过滤器链匹配,如果能够匹配,则将对应增强器返回。
MethodInvocation
当找到过滤器链后,会构造一个 ReflectiveMethodInvocation
开始执行链路。
public Object proceed() throws Throwable {
// 如果执行按了,那么直接执行对应方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 通过索引,获取下一个链
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 执行 InterceptorAndDynamicMethodMatcher 操作。
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 执行对应方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
整个执行链路可以总结为:
- 每当命中要拦截方法,则会获取所有advisor的执行器链。
- 最后进入
retVal = invocation.proceed();
执行所有链路。 - 通过自带
currentInterceptorIndex
变量标识顺序,而不需要重新进入JdkDynamicAopProxy
拦截 - 执行完后,如果有返回值,则返回对应值。
觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring: