攔截器總結:
總結執行順序:
preHandle按攔截器定義順序調用
postHandler按攔截器定義逆序調用
afterCompletion按攔截器定義逆序調用
postHandler在攔截器鏈內全部攔截器返成功調用
afterCompletion只有preHandle返回true才調用複製代碼
在applicationContext中存在一個beanFactoryjava
進去beanFactory能夠看到beanPostProcessorsweb
進去beanPostProcessors能夠看到AnnotationAwareAspectJAutoProxyCreator
spring
進去AnnotationAwareAspectJAutoProxyCreator能夠看到beanFactory和proxyType和adviseBeans
api
進去beanFactory的singletonObjects能夠看到mathTest代理類,代開一個攔截器,能夠看到裏面全部咱們後面源碼分析的一些參數。好比active=true,targetSource,advisors等
springboot
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}複製代碼
進入註解EnableAspectJAutoProxy能夠發現@Import(AspectJAutoProxyRegistrar.class),注入了一個AspectJAutoProxyRegistrar的組件,咱們在看看AspectJAutoProxyRegistrar裏面代碼bash
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
複製代碼
從上面的代碼能夠看出在ioc初始化的時候BeanDefinition中保存了name爲org.springframework.aop.config.internalAutoProxyCreator,類爲AnnotationAwareAspectJAutoProxyCreator的Bean定義信息。app
接下來看看AnnotationAwareAspectJAutoProxyCreatoride
先看看繼承關係
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator;
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator;
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator ;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport;
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware;
從這裏能夠看出他的父類實現了SmartInstantiationAwareBeanPostProcessor
, BeanFactoryAware這兩個接口,
看看後置處理器作了什麼?
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}從上面的代碼能夠看出他將全部的代理類的加強攔截器(before,after等,加上事務管理的TransationInterceptor),目標類等,都會
整理出來保存到代理類中。到這裏其實前置條件已經基本完成了。le複製代碼
package com.felix.springbootdemo.aspects;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
@Aspect
@Slf4j
public class MathAspect {
@Pointcut("execution(public * com.felix.springbootdemo.test.*.*(..))")
public void test() {
}
@Before("test()")
public void doBefore(JoinPoint joinPoint) {
//獲取方法名稱
String name = joinPoint.getSignature().getName();
//獲取參數
List<Object> list = Arrays.asList(joinPoint.getArgs());
log.info("方法{}前置加強,參數爲:{}", name, list);
}
@After("test()")
public void doAfter(JoinPoint joinPoint) {
//獲取方法名稱
String name = joinPoint.getSignature().getName();
//獲取參數
List<Object> list = Arrays.asList(joinPoint.getArgs());
log.info("方法{}後置加強,參數爲:{}", name, list);
}
@AfterReturning(value = "test()", returning = "returning")
public void doAfterReturning(JoinPoint joinPoint, Object returning) {
//獲取方法名稱
String name = joinPoint.getSignature().getName();
//獲取參數
List<Object> list = Arrays.asList(joinPoint.getArgs());
log.info("方法{}返回加強,參數爲:{},返回值爲:{}", name, list, returning);
}
@AfterThrowing(value = "test()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
//獲取方法名稱
String name = joinPoint.getSignature().getName();
//獲取參數
List<Object> list = Arrays.asList(joinPoint.getArgs());
log.info("方法{}異常加強,參數爲:{},異常爲:{}", name, list, e.getMessage());
}
}複製代碼
package com.felix.springbootdemo.config;
import com.felix.springbootdemo.aspects.MathAspect;
import com.felix.springbootdemo.test.MathTest;
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
public class AopConfig {
@Bean
public MathTest mathTest() {
return new MathTest();
}
@Bean
public MathAspect mathAspect() {
return new MathAspect();
}
}複製代碼
package com.felix.springbootdemo.test;
public class MathTest {
public int div(int x, int y) {
return x / y;
}
}
複製代碼
package com.felix.springbootdemo.config;
import com.felix.springbootdemo.test.MathTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Slf4j
public class Test {
@org.junit.jupiter.api.Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
MathTest bean = applicationContext.getBean(MathTest.class);
log.info("{}", bean);
bean.div(1, 1);
}
}複製代碼
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
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);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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 = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}複製代碼
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);這個方法是獲取攔截器鏈,其中在獲取攔截器的時候,在使用適配器模式將全部的攔截器封裝成Advisor源碼分析
再看看執行的方法post
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
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 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); } }複製代碼
裏面有三個地方值得關注
一、this.currentInterceptorIndex=-1
二、Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
複製代碼
三、return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
下面的圖片爲執行的過程圖。