Spring思维导图 SpringAOP切面解析流程图 SpringAOP创建代理流程图
AOP (Aspect Oriented Programming)
AOP 面向切面编程,要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。AOP 的实现并不是因为 Java 提供了神奇的钩子,可以把方法的几个生命周期告诉我们,而是我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。
AOP 术语解释
- 切面(Aspect): 在 AOP 中指切面类 (通常被 @Aspect 标注),管理着通知和切点
- 连接点(Join Point): 切面和被增强方法所连接的点(即代理方法,我们需要增强的方法)
- 通知(Advice): 某个特点的连接点上执行的动作,通常包括 前置(Before),后置(After),异常(Exeception),环绕(Around)
- 目标对象(Target): 需要被增强的对象,即包含业务逻辑类的对象
- 切点(PointCut): 匹配连接点的断言,由其决定哪些方法需要被增强,哪些不需要被增强,是AOP核心。Spring 默认使用 AspectJ 切点语义
- 顾问(Advisor): 通知 (Advice) 的一种包装体现。是 Advice 和 PointCut 的结合,无需应用关心
- 织入(Weaving): 将通知切入连接点的过程
- 引入(Introductions): 将其他接口和实现动态的引入targetClass中,不常用
AspectJ
AspectJ 是 AOP 编程的完全解决方案,它能做许多AOP实现不了的事情。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入)。
SpringAOP中的 @Aspect、@PointCut、@Before、@After、@Around 都来自 AspectJ,但功能都有 SpringAOP自己实现
SpringAOP
-
它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现 1、如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP,可以强制使用 CGLIB 实现 2、如果目标对象没有实现了接口,必须采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 之间转换 -
Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,不需要显式引入依赖 -
Spring AOP 需要依赖于 IOC 容器来管理 -
Spring AOP 只能作用于 Spring 容器中的 Bean,使用纯粹的 Java 代码实现的,只能作用于 Bean 的方法 -
Spring 提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配
Spring AOP 的配置方式
Spring AOP 一共有三种配置方式,并且做到了很好的向下兼容
- Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的,Spring 的事务就是此方式实现的
- Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用命名空间
- Spring 2.0 @AspectJ配置:使用注解的方式来配置
@EnableAspectJAutoProxy
基于接口:
首先定义需要被增强的类:
接口:Calculate.java 实现类:TestCalculate.java
public interface Calculate {
int add(int numA, int numB);
int sub(int numA, int numB);
int multi(int numA, int numB);
int div(int numA, int numB);
}
public int add(int numA, int numB) {
System.out.println("Invoke Method:add");
System.out.println(1/0);
return numA+numB;
}
public int sub(int numA, int numB) {
System.out.println("Invoke Method:reduce");
return numA-numB;
}
public int div(int numA, int numB) {
System.out.println("Invoke Method:div");
return numA/numB;
}
public int multi(int numA, int numB) {
System.out.println("Invoke Method:multi");
return numA*numB;
}
第二步:配置 advice 或 Interceptor
public class TestLogAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String methodName = method.getName();
System.out.println("invoke method " + methodName + "() <BeforeAdvice>,args" + Arrays.asList(args));
}
}
public class TestLogInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(getClass()+"Before Invoke");
Object ret=invocation.proceed();
System.out.println(getClass()+"After Invoke");
return ret;
}
}
最后配置配置类:
@Bean
public Calculate testCalculate() {
return new TestCalculate();
}
@Bean
public TestLogAdvice testLogAdvice(){
return new TestLogAdvice();
}
@Bean
public TestLogInterceptor testLogInterceptor() {
return new TestLogInterceptor();
}
@Bean
public ProxyFactoryBean calculateProxy(){
ProxyFactoryBean userService=new ProxyFactoryBean();
userService.setInterceptorNames("testLogAdvice","testLogInterceptor");
userService.setTarget(testCalculate());
return userService;
}
测试类与运行结果:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
calculateProxy.div(1,1);
}
--------------------执行结果--------------------
invoke method div() <BeforeAdvice>,args[1, 1]
class zhe.hello.aop.TestLogInterceptor Before invoke Method
Invoke Method:div
class zhe.hello.aop.TestLogInterceptor After invoke Method
从结果可以看到,使用了责任链方式对 advice 和 Interceptor 都进行调用。这个例子理解起来应该非常简单,就是通过调用 FactoryBean(ProxyFactoryBean) 的 getObject() 方法创建一个代理实现。责任链的两个重要依靠:统一抽象、循环或递归。
但是这种方式存在几个指明缺点:
- 只能指定单一的 Bean 的 AOP,多个 Bean 需要创建多个 ProxyFactoryBean
- 添加一个通知我们就需要配置一个 MethodXxxxAdvice 或 MethodInterceptor 类
- 拦截器的粒度只控制到了类级别,类中所有的方法都进行了拦截
在上面的配置中,配置拦截器的时候,interceptorNames 除了指定为 Advice,是还可以指定为 Interceptor 和 Advisor 的。这里我们来理解 Advisor 的概念,它是经过包装后的细粒度控制方式,它内部需要指定一个 Advice,Advisor 决定该拦截哪些方法 (即 Advice + PointCut),拦截后需要完成的工作还是内部的 Advice 来做。 它内部有多个实现,我们以NameMatchMethodPointcutAdvisor 为例,顾名思义,就是通过提供方法的名字,复合的就进行拦截。
@Bean
public NameMatchMethodPointcutAdvisor testLogAspectAdvisor() {
NameMatchMethodPointcutAdvisor advisor=new NameMatchMethodPointcutAdvisor();
advisor.setAdvice(testLogAdvice());
advisor.setMappedNames("div");
return advisor;
}
@Bean
public RegexpMethodPointcutAdvisor testLogAspectInterceptor() {
RegexpMethodPointcutAdvisor advisor=new RegexpMethodPointcutAdvisor();
advisor.setAdvice(testLogInterceptor());
advisor.setPattern("test.TestCalculate.*");
return advisor;
}
@Bean
public ProxyFactoryBean calculateProxy(){
ProxyFactoryBean userService = new ProxyFactoryBean();
userService.setInterceptorNames("testLogAspectAdvisor");
userService.setTarget(testCalculate());
return userService;
}
从上述代码中可以看到calculateProxy 这个 bean 配置了一个advisor ,内部还可以指定切点,设置更细粒度的控制,从方法级别继续拦截,不在局限于类。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
System.out.println(calculateProxy.getClass());
calculateProxy.div(1,1);
--------------------执行结果--------------------
invoke method div() <BeforeAdvice>,args[1, 1]
Invoke Method:div
但是面所有的实现都存在一个共同的问题,它们都得为每个 bean 都配置一个代理,之后获取 bean 的时候需要获取这个代理类的 bean 实例(例如ctx.getBean("calculateProxy",Calculate.class) )。那么怎么才能实现自动根据类型注入呢?下面介绍 autoproxy 的解决方案。
autoproxy:顾名思义就是实现自动代理,当 Spring 发现一个 bean 需要被切面织入的时候,Spring 会自动生成这个 bean 的一个代理来拦截方法的执行,确保定义的切面能被执行。
下面我们可以去掉原来的 ProxyFactoryBean 的配置,改为使用 BeanNameAutoProxyCreator 来配置:
@Bean
public BeanNameAutoProxyCreator autoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("test*");
beanNameAutoProxyCreator.setInterceptorNames("testLogAspectAdvisor");
return beanNameAutoProxyCreator;
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EalyAopMainConfig.class);
Calculate calculateProxy = ctx.getBean("calculateProxy",Calculate.class);
System.out.println(calculateProxy.getClass());
calculateProxy.div(1,1);
calculateProxy.add(1,1);
--------------------执行结果--------------------
class com.sun.proxy.$Proxy11
invoke method div() <BeforeAdvice>,args[1, 1]
invoke method div() <BeforeAdvice>,args[1, 1]
Invoke Method:div
Invoke Method:add
从执行结果可以发现,我们在使用时已经完全不需要关心代理,直接使用原来的类型即可。例如我们使用BeanNameAutoProxyCreator ,它只需要指定被拦截类名的模式 (如 *ServiceImpl),它可以配置多次,这样就可以用来匹配不同模式的类了。
当然,我们也可以不配置BeanNameAutoProxyCreator autoProxyCreator() 直接使用下面的配置,让所有的 Advisor 自动生效。也就不需要autoProxyCreator() 的配置了
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
到这里,已经可以看出能够十分方便的创建代理了,基于注解形式的也就是在此基础上进行改造读取切面类,及方法上的注解而已。
下面是基于注解形式的实现
切面类:
@Aspect
@Order
@Component
public class TestLogAspect {
@DeclareParents(value="cn.zhe.hello.aop.TestCalculate",
defaultImpl = SimpleProgramCalculate.class)
public static ProgramCalculate programCalculate;
@Pointcut("execution(* cn.zhe.hello.aop.TestCalculate.*(..))")
public void pointCut(){};
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Before Advice>,args"+ Arrays.asList(joinPoint.getArgs()));
}
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <After Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()",returning = "result")
public void methodReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Return Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()")
public void methodAfterThrowing(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Invoke Method "+methodName+"() <Exception Advice>,args"+Arrays.asList(joinPoint.getArgs()));
}
}
测试类及运行结果:
public class TestMainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
Calculate calculate = (Calculate) ctx.getBean("testCalculate");
int retVal = calculate.div(2,4);
}
}
--------------------执行结果--------------------
Invoke Method div() <Before Advice>,args[2, 4]
Invoke Method:div
Invoke Method div() <Return Advice>,args[2, 4]
Invoke Method div() <After Advice>,args[2, 4]
SpringAOP 源码解析
相信大家都指定 Spring 中的 AOP 是通过动态代理来实现的。Spring 通过一个 @EnableAspectJAutoProxy 注解开启AOP,Spring 通过定义一个切面类 (标注@Aspect) ,并定义一个 @Pointcut 方法,最后再定义一些列的增强方法,就能完成一些列的对象切面操作。增强方法类型如下:
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
由我们上面所了解到的知识,可以推测出它大概分为以下几个步骤:
- 找到所有的切面类并解析 (解析切面类)
- 解析出所有的 Advice 并保存 (缓存通知)
- 创建一个动态代理 (JDK OR CGLIB)
- 调用被代理类的方法时,找到所有增强 (Advice),并增强方法
先来看一下整体流程图 下面我们来逐步分解源码
一、注册 Bean的后置处理器
首先 Spring 通过一个 @EnableAspectJAutoProxy 注解开启AOP,点进去我们可以发现,在注解类上面发现了另一个注解 @Import(AspectJAutoProxyRegistrar.class),该类实现了 ImportBeanDefinitionRegistrar ,所以他会通过registerBeanDefinitions() 为容器导入 BeanDefinition。
在postProcessBeforeInstantiation中解析切面逻辑将在后文解释。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented1
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {}
二、解析切面类
在我们的创建Bean调用doCreatBean() 方法之前会调用 applyBean
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
然后走到AbstractAutoProxyCreator 的postProcessBeforeInstantiation() 方法
@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;
}
}
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;
}
有两种类型表示该bean不能被增强:1.是切面类型的;2.是原始类型的,原始bean 的后缀是有.ORIGINAL 标志的。下面进入 AspectJAwareAdvisorAutoProxyCreator.java 的shouldSkip 方法,注意千万不要找错了。
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
然后进入 AnnotationAwareAspectJAutoProxyCreator.java 的findCandidateAdvisors() 方法,它找到接口,注解相关的 Advisor。
@Override
protected List<Advisor> findCandidateAdvisors() {
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
protected List<Advisor> findCandidateAdvisors() {
return this.advisorRetrievalHelper.findAdvisorBeans();
}
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
} else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
}
}
}
}
return advisors;
}
然后进入buildAspectJAdvisors() 方法
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
然后就进入到了getAdvisors() 方法,执行解析切面类的详细逻辑
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
然后看一下getAdvisor() 方法
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
最后解析构建的通知对象ReflectiveAspectJAdvisorFactory 的getAdvice() 方法
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
至此我们解析切面就结束了,此时我们的注解、接口、xml标注的切面、切点等都会被解析。
三、创建代理
创建代理又可以分为三个步骤
- 获取 Advisors
- Advisors 匹配切点
- 创建代理
① 获取 Advisors
@Override
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;
}
@Override
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;
}
然后进入wrapIfNecessary() 方法,该方法会去寻找方法,判断是否能且需要被代理,并代理它
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;
}
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;
}
再进入到 getAdvicesAndAdvisorsForBean() 方法,找到合适的通知,在这里我们会发现又链到了上面我吗解析切面类中的的findCandidateAdvisors() 方法,由于我们**之前已经解析了切面、切点并进行了缓存 (切面类的BeanName) 所以只需要到缓存中去取就行了**。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
② Advisors 匹配切点
从上一步的代码中进入到findAdvisorsThatCanApply() 方法,匹配切点
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
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) {
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
然后再进入canApply() 会对筛选出来的Advisor 拿到切点后进行初筛和精筛,获取到合适的增强。关于初筛和精筛就不过多的叙述了,主要功能如下:
- **初筛: **类级别的过来,通过 AspectJ
- 精筛: 匹配所有方法,按切点表达式和方法匹配器匹配,只要有一个匹配上就创建代理
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
③ 创建代理
再次回到wrapIfNecessary() 方法,调用createProxy() 方法,原理就是:先判断是否设置了 proxyTargetClass=true 如果是创建 CGLIB 代理,在判断是否有接口,有接口创建 JDK 代理,无接口创建 CGLIB 代理。
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());
}
四、代理类的调用
前面已经自己做了基于 Advisor 的 AOP,那么 Spring 也是这样,在执行时,只需要将这些增强添加到被代理的类上即可。
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
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();
}
}
}
然后将增强器装换为方法拦截器链,最终包装为ReflectiveMethodInvocation执行它的proceed 方法,以 JDK 代理为例
@Override
@Nullable
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) {
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 {
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
然后进入到ExposeInvocationInterceptor.java 的invoke() 方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
AspectJAfterAdvice 的invoke() 方法,返回拦截器,方法执行失败,不会调用
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice 的invoke() 方法,后置拦截器,总是执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
MethodBeforeAdviceInterceptor 的invoke() 方法,后置拦截器,总是执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
ThrowsAdviceInterceptor 的invoke() 方法,异常拦截器,异常时执行
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
看到上面的几个通知执行方法没有?都在调用mi.proceed() 就是责任链的递归调用,将所有的通知切入我们的增强类中,SpringAOP就实现了。
|