项目搭建

为了更好地阐述AOP的原理,这里我们来实现一个简单地需求,计算除法。 下面的代码中分别创建了一个计算类和一个计算代理类,熟悉SpringAOP开发的读者应该非常熟悉下面的代码格式。
实现下面的代码需要添加依赖:

  1. compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'
  2. compile group: 'org.springframework', name: 'spring-context', version: '5.2.6.RELEASE'

定义 MathCalculator 用户被代理,实现一个整数的除法;定义 MathCalculatorAspect 用户实现AOP 代理,切入点 execution(public double com.zhoutao123.spring.aop.MathCalculator.*(..)) 分别实现前置通知,后置通知,环绕通知以及异常通知(其他通知方式,读者可以自己实现测试)

  1. // 定义目标代理类
  2. public class MathCalculator {
  3. public double div(Integer a, Integer b) {
  4. System.out.println("调用业务代码");
  5. return a * 1.0 / b;
  6. }
  7. }
  8. // 定义代理类
  9. @Aspect
  10. public class MathCalculatorAspect {
  11. @Pointcut("execution(public double com.zhoutao123.spring.aop.MathCalculator.*(..))")
  12. public void pointCut() {
  13. }
  14. @Before("pointCut()")
  15. public void before(JoinPoint joinPoint) {
  16. Signature signature = joinPoint.getSignature();
  17. System.out.println("Before 方法名称:" + signature.getName() + " 参数表:" + Arrays
  18. .toString(joinPoint.getArgs()));
  19. }
  20. @After("pointCut()")
  21. public void after() {
  22. System.out.println("后置执行");
  23. }
  24. @AfterReturning(value = "pointCut()", returning = "result")
  25. public void afterReturning(Object result) {
  26. System.out.println("返回值:" + (result == null ? "null" : result.toString()));
  27. }
  28. @AfterThrowing(value = "pointCut()", throwing = "exception")
  29. public void afterThrowing(Exception exception) {
  30. System.out.println("异常信息:" + (exception == null ? "null" : exception.getMessage()));
  31. }
  32. }

同时需要创建一个配置类,用于启动Spring项目以及注入 MathCalculator & MathCalculatorAspect ,执行main方法可以看到代理日志的输出

  1. @Configurable
  2. @EnableAspectJAutoProxy
  3. public class MainConfigOfAOP {
  4. @Bean
  5. public MathCalculator matchCalculator() {
  6. return new MathCalculator();
  7. }
  8. @Bean
  9. public MathCalculatorAspect aspect() {
  10. return new MathCalculatorAspect();
  11. }
  12. public static void main(String[] args) {
  13. AnnotationConfigApplicationContext
  14. context = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
  15. MathCalculator bean = context.getBean(MathCalculator.class);
  16. bean.div(1, 0);
  17. }
  18. }
  19. // 输出日志
  20. Before 方法名称:div 参数表:[18, 3]
  21. 调用业务代码
  22. 后置执行
  23. 返回值:6.0

源码分析

细心地读者可能发现,在MainConfigOfAOP的类中,出现了一个注解 @EnableAspectJAutoProxy 这个注解使用常见的SPring提供的 @EnableXXXX 类型的注解,这个注解非常重要,使用@Import注解 导入需要的Bean类型对象。

  1. @Configurable
  2. @EnableAspectJAutoProxy
  3. public class MainConfigOfAOP {}
  4. @Target(ElementType.TYPE)
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. @Import(AspectJAutoProxyRegistrar.class)
  8. public @interface EnableAspectJAutoProxy {}

EnableAspectJAutoProxy 注解

如上文所示,EnableASpectJAutoProxy注解导入 @Import(AspectJAutoProxyRegistrar.classAspectJAutoProxyRegistrar 是一个 ImportBeanDefinitionRegistrar ,ImportBeanDefinitionRegistrar 可以向IOC中注册BeanDefinition。AspectJAutoProxyRegistrar 会向Spring的容器中注入一个类型为 AnnotationAwareAspectJAutoProxyCreator 的BeanPostProcessor(后置处理器)用户处理Bean对象。

image.png

关于 ImportBeanDefinitionRegistrar 导入Bean的注册器 以及 BeanPostProcessor 后置处理器,在笔者的同栏文章,均有详细的阐述,对这里不太明白的,可以查阅这些文章或者留言!

  1. @Nullable
  2. private static BeanDefinition registerOrEscalateApcAsRequired(
  3. Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  4. // .....
  5. RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  6. beanDefinition.setSource(source);
  7. beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
  8. beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  9. registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  10. return beanDefinition;
  11. }

AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器,继承了 BeanPostProcessor ,AspectJAutoProxyRegistrar 想SpringIOC 注入这个Bean的定义之后,Sprin会在之后创建这个对象实例。
image.png

Spring容器启动

容器启动后AnnotationAwareAspectJAutoProxyCreator 被创建,并且被收到IOC 的后置处理器集合中,然后继续执行创建Bean,创建Bean的过程中获取遍历后置处理器,分别来进行处理这些Bean。

  1. // 所在类 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
  2. @Override
  3. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  4. if (bean != null) {
  5. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  6. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  7. // 调用方法,判断是否需要封装(即是否需要被代理)
  8. return wrapIfNecessary(bean, beanName, cacheKey);
  9. }
  10. }
  11. return bean;
  12. }
  13. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  14. // .......
  15. // 获取增强点,如果增强点不存在,则不在创建代理,否则执行createProxy() 方法创建代理对象
  16. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  17. if (specificInterceptors != DO_NOT_PROXY) {
  18. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  19. Object proxy = createProxy(
  20. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  21. this.proxyTypes.put(cacheKey, proxy.getClass());
  22. return proxy;
  23. }
  24. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  25. return bean;
  26. }

而创建代理对象createProxy() 方法的核心类为 ProxyFactory
**

  1. protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
  2. @Nullable Object[] specificInterceptors, TargetSource targetSource) {
  3. //....
  4. ProxyFactory proxyFactory = new ProxyFactory();
  5. proxyFactory.copyFrom(this);
  6. // 获取增强点信息
  7. Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  8. // 封装到 ProxyFactory 中
  9. proxyFactory.addAdvisors(advisors);
  10. proxyFactory.setTargetSource(targetSource);
  11. // 模板方法,忽略
  12. customizeProxyFactory(proxyFactory);
  13. proxyFactory.setFrozen(this.freezeProxy);
  14. if (advisorsPreFiltered()) {
  15. proxyFactory.setPreFiltered(true);
  16. }
  17. // 生成代理对象
  18. return proxyFactory.getProxy(getProxyClassLoader());
  19. }

众所周知,Spring生成代理对象有两种方式: JDK & Cglib, DefaultAopProxyFactory 的代码中提供了说明

  1. @Override
  2. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  3. if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  4. Class<?> targetClass = config.getTargetClass();
  5. if (targetClass == null) {
  6. throw new AopConfigException("TargetSource cannot determine target class: " +
  7. "Either an interface or a target is required for proxy creation.");
  8. }
  9. // 如果代理类是接口 或者 是一个代理类,则直接走JDK动态代理,否则走Cglib代理
  10. if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  11. return new JdkDynamicAopProxy(config);
  12. }
  13. return new ObjenesisCglibAopProxy(config);
  14. }
  15. else {
  16. return new JdkDynamicAopProxy(config);
  17. }
  18. }


**

JDK 方式实现动态代理

JDK的动态代理是通过实现 InvocationHandler实现了,然后重写invoke方法,这和我们之前的项目中使用JDK动态代理的方式是一致的。

  1. final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
  2. // ...... 省略代码
  3. @Override
  4. @Nullable
  5. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  6. Object oldProxy = null;
  7. boolean setProxyContext = false;
  8. TargetSource targetSource = this.advised.targetSource;
  9. Object target = null;
  10. // 获取目标方法的拦截链
  11. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  12. // 如果拦截链为空,则使用反射的方法执行,否则生成MethodInvocation,进行执行
  13. if (chain.isEmpty()) {
  14. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  15. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  16. }
  17. else {
  18. MethodInvocation invocation =
  19. new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  20. retVal = invocation.proceed();
  21. }

Cglib 方式实现动态代理

Cglib 动态代理是基于字节码实现的,因此性能相对于JDK代理而言较高。一般情况下,Cglib的代理生成类如下所示:

  1. // 定义拦截器
  2. public class MyMethodInterceptor implements MethodInterceptor{
  3. @Override
  4. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  5. System.out.println("调用代理方法");
  6. return proxy.invokeSuper(obj, args);
  7. }
  8. }
  9. //创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
  10. Enhancer enhancer = new Enhancer();
  11. //设置目标类的字节码文件
  12. enhancer.setSuperclass(Cat.class);
  13. //设置回调函数
  14. enhancer.setCallback(new MyMethodInterceptor());
  15. //这里的creat方法就是正式创建代理类
  16. Cat proxyCat = (Cat)enhancer.create();
  17. //调用代理类的eat方法
  18. proxyCat.eat();

而在Sprint中使用CGlib实现代理的方式也是大同小异,具体分析如下:

  1. @Override
  2. public Object getProxy() {
  3. return getProxy(null);
  4. }
  5. @Override
  6. public Object getProxy(@Nullable ClassLoader classLoader) {
  7. if (logger.isTraceEnabled()) {
  8. logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
  9. }
  10. try {
  11. // 获取代理目标类
  12. Class<?> rootClass = this.advised.getTargetClass();
  13. // Configure CGLIB Enhancer...
  14. Enhancer enhancer = createEnhancer();
  15. if (classLoader != null) {
  16. enhancer.setClassLoader(classLoader);
  17. if (classLoader instanceof SmartClassLoader &&
  18. ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
  19. enhancer.setUseCache(false);
  20. }
  21. }
  22. // 设置Cglib代理的目标类等配置信息
  23. enhancer.setSuperclass(proxySuperClass);
  24. enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
  25. enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
  26. enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
  27. // 生成回调方法
  28. Callback[] callbacks = getCallbacks(rootClass);
  29. Class<?>[] types = new Class<?>[callbacks.length];
  30. for (int x = 0; x < types.length; x++) {
  31. types[x] = callbacks[x].getClass();
  32. }
  33. // fixedInterceptorMap only populated at this point, after getCallbacks call above
  34. enhancer.setCallbackFilter(new ProxyCallbackFilter(
  35. this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
  36. enhancer.setCallbackTypes(types);
  37. // 直接生成代理类,并返回实例对象
  38. return createProxyClassAndInstance(enhancer, callbacks);
  39. }
  40. catch (CodeGenerationException | IllegalArgumentException ex) {
  41. throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
  42. ": Common causes of this problem include using a final class or a non-visible class",
  43. ex);
  44. }
  45. catch (Throwable ex) {
  46. // TargetSource.getTarget() failed
  47. throw new AopConfigException("Unexpected AOP exception", ex);
  48. }
  49. }
  50. protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
  51. enhancer.setInterceptDuringConstruction(false);
  52. enhancer.setCallbacks(callbacks);
  53. return (this.constructorArgs != null && this.constructorArgTypes != null ?
  54. enhancer.create(this.constructorArgTypes, this.constructorArgs) :
  55. enhancer.create());
  56. }