业务类:
package com.cjian.aop;
/**
* @description:
* @author: cWX969834
* @time: 2020/11/4 9:06
*/
public class MathCalculator {
public int div(int a, int b) {
System.out.println("除法。。。");
return a / b;
}
}
切面类:
package com.cjian.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import java.util.Arrays;
/**
* @description:切面类,业务增强类
* @author: cWX969834
* @time: 2020/11/4 9:07
*/
@Aspect
public class LogAspects {
//抽取公共的切入点表达式
//1.本类引用 如 logStart
//2.外部类引用 如 logEnd
@Pointcut("execution(public int com.cjian.aop.MathCalculator.*(..))")
public void pointCut(){}
//在方法运行之前
@Before("pointCut()")
public void logStart(JoinPoint jp) {
System.out.println(jp.getSignature().getName()+" 开始运行..."+"参数为 :"+ Arrays.asList(jp.getArgs()));
}
//在方法运行之后(无论方法是否正常运行)
@After("com.cjian.aop.LogAspects.pointCut()")
public void logEnd(JoinPoint jp) {
System.out.println(jp.getSignature().getName()+" 运行结束...");
}
//在方法正常运行之后
@AfterReturning(value="pointCut()",returning = "result")
public void logReturn(JoinPoint jp,Object result) {
System.out.println(jp.getSignature().getName()+" 运行结束...结果为:"+result);
}
//在方法出现异常之后运行
@AfterThrowing(value = "pointCut()",throwing = "exception")
public void logException(JoinPoint jp,Exception exception) {
System.out.println(jp.getSignature().getName()+" 发生异常..."+exception);
}
}
配置类:
package com.cjian.config;
import com.cjian.aop.LogAspects;
import com.cjian.aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @description:
* @author: cWX969834
* @time: 2020/10/28 9:32
*/
@Configuration //告诉spring这是一个配置类
@EnableAspectJAutoProxy//开启AOP
public class MainConfigAOP {
@Bean
public MathCalculator mathCalculator(){
return new MathCalculator();
}
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
测试类:
package com.cjian;
import com.cjian.aop.MathCalculator;
import com.cjian.config.MainConfigAOP;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @description:
* @author: cWX969834
* @time: 2020/11/3 11:13
*/
public class TestAOP {
static AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(
MainConfigAOP.class);
public static void main(String[] args) {
MathCalculator mathCalculator = annotationConfigApplicationContext.getBean(MathCalculator.class);
mathCalculator.div(1, 0);
}
}
输出:
div 开始运行...参数为 :[1, 0]
除法。。。
div 发生异常...java.lang.ArithmeticException: / by zero
div 运行结束...
Exception in thread "main" java.lang.ArithmeticException: / by zero
......后面异常信息省略
正常运行时:
div 开始运行...参数为 :[1, 1]
除法。。。
div 运行结束...结果为:1
div 运行结束...
AOP的一个小实践就搞定了,那么AOP的原理是啥呢?
让我们从@EnableAspectJAutoProxy注解入手,看看这个注解都干了啥?
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
使用@Import注解给容器中注册了一个AspectJAutoProxyRegistrar,这个类是干啥的呢?
package org.springframework.context.annotation;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
AspectJAutoProxyRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//重点,这里来个断点
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
debug发现通过几个方法的调用,最终来到了这里
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
//clas :org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
} else {
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;
}
}
为了给容器中注册一个id 为org.springframework.aop.config.internalAutoProxyCreator,实例为org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator 的组件
总结:@EnableAspectJAutoProxy 的功能?
通过@Import({AspectJAutoProxyRegistrar.class}) 给容器中导入了一个AspectJAutoProxyRegistrar,利用AspectJAutoProxyRegistrar自定义给容器中注册一个id 为org.springframework.aop.config.internalAutoProxyCreator,实例为org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator 的组件
那么 AnnotationAwareAspectJAutoProxyCreator又是什么呢?
查看该类的体系:
第一点不管它,主要看右边即第二点,关注后置处理器在bean初始化完成前后做了什么事,以及第三点自动装配BeanFactory
接下来我们重点关注每个类都干了什么,因为各种继承/实现关系,我们先从最顶层的父类即AbstractAutoProxyCreator开始分析:
发现有以下三我们需要重点关注的方法
接下来是AbstractAdvisorAutoProxyCreator,它又重写了父类的setBeanFactory方法,并在里面调用了initBeanFactory方法
接下来是AspectJAwareAdvisorAutoProxyCreator ,没有什么需要关注的,跳过
然后是AnnotationAwareAspectJAutoProxyCreator,这里它又重写了initBeanFactory方法,需要关注
创建和注册AnnotationAwareAspectJAutoProxyCreator的过程
1)、传入配置类,创建IOC容器
2)、注册配置类,调用refresh()刷新容器
3)、registerBeanPostProcessors(),注册bean的后置处理器来方便拦截bean的创建;1)、先获取ioc容器已经定义的需要创建对象的所有BeanPostProcessor
2)、先给容器中加别的BeanPostProcessor
3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor4)、再给容器中注册实现了Ordered接口的接口的BeanPostProcessor
AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口
5)、注册没有实现优先级接口的接口的BeanPostProcessor
6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】PS:getBean最终会调用到org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法,该方法还涉及了spring的循环依赖问题,以后再说
1)、创建Bean的实例;finishBeanFactoryInitialization:完成BeanFactory初始化工作,创建剩下的单实例bean
doGetBean方法:先从缓存中获取当前bean,如果能获取到,说明bean之前被创建过,直接使用,否则再创建(只要创建好的bean都会被缓存起来这也是spring保证单实例只会被创建一次的机制)
AnnotationAwareAspectJAutoProxyCreator刚好是InstantiationAwareBeanPostProcessor的子类
最终来到这了,下面这张截图也是AnnotationAwareAspectJAutoProxyCreator的作用了,后面分析
2)、populateBean:给bean的各种属性赋值;
3)、initializeBean:初始化bean;该步骤之前说过,不再细说了
1)、invokeAwareMethods:处理Aware接口的方法回调
2)、applyBeanPostProcessorsBeforeInitialization
3)、invokeInitMethods:执行自定义的初始化方法
4)、applyBeanPostProcessorsAfterInitialization4)、BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】创建成功,并调用initBeanFactory
7)、把BeanPostProcessor注册到BeanFactory中:beanFactory.addBeanPostProcessor