AOP的相关术语

先说明AOP的这些术语想要做什么事? 其实就是要确定在哪些方法中的哪些地方去插入横切逻辑。

连接点 JointPoint

连接点其实是时机点,也就是可以插入横切逻辑代码的时机,比如说方法开始执行时、方法结束时、方法异常结束时等,连接点也被称为候选点,是切入点的候选点。

切入点 PonitCut

真正被横切逻辑代码增强的方法就是切入点,也就是我们需要增强的方法。

Advice增强

说的就是横切逻辑以及时机点(方位点),分类有前置通知、后置通知、环绕通知、异常通知、最终通知。

织入 Weaving

将增强插入到切点的过程,就是织入。

切面 Aspect

说的就是advice增强织入到切入点的这整个一件事。

代码实现

xml方式

直接代码进行展示,流程就是先导入相关依赖,然后声明一个Aop的类,在xml中进行相关配置

  1. pom依赖如下:
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-aop</artifactId>
  5. <version>5.2.10.RELEASE</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.aspectj</groupId>
  9. <artifactId>aspectjweaver</artifactId>
  10. <version>1.9.5</version>
  11. </dependency>
  1. Aop的类,其实就是一个工具类
  2. public class AopUtils {
  3. public void before(JoinPoint joinPoint) {
  4. Object[] args = joinPoint.getArgs();
  5. for (Object arg : args) {
  6. System.out.println("前置通知的参数为:" + arg);
  7. }
  8. System.out.println("前置通知结束");
  9. }
  10. public void after(JoinPoint joinPoint) {
  11. System.out.println("后置通知结束");
  12. }
  13. public void exception(JoinPoint joinPoint) {
  14. System.out.println("异常通知结束");
  15. }
  16. public void finallyAdvice() {
  17. System.out.println("最终通知");
  18. }
  19. public void returnAdvice() {
  20. System.out.println("正常返回通知");
  21. }
  22. public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  23. System.out.println("环绕通知前置");
  24. proceedingJoinPoint.proceed();
  25. System.out.println("环绕通知后置");
  26. }
  27. }
  1. // 进行applicationContext.xml的配置
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <beans default-lazy-init="false" xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xmlns:aop="http://www.springframework.org/schema/aop"
  7. xsi:schemaLocation="http://www.springframework.org/schema/beans
  8. https://www.springframework.org/schema/beans/spring-beans.xsd
  9. http://www.springframework.org/schema/context
  10. https://www.springframework.org/schema/context/spring-context.xsd
  11. http://www.springframework.org/schema/aop
  12. https://www.springframework.org/schema/aop/spring-aop.xsd">
  13. <beans>
  14. <bean id="aopUtils" class="com.wangzhi.util.AopUtils"/>
  15. <bean id="user" class="com.wangzhi.domain.User"/>
  16. <aop:config>
  17. <aop:aspect id="aop" ref="aopUtils">
  18. <!--配置切入点-->
  19. <aop:pointcut id="userSetName" expression="execution(public void com.wangzhi.domain.User.setName(String))"/>
  20. <!--配置前置后置等相关通知-->
  21. <aop:before method="before" pointcut-ref="userSetName"/>
  22. <aop:after method="finallyAdvice" pointcut-ref="userSetName"/>
  23. <aop:after-returning method="returnAdvice" pointcut-ref="userSetName"/>
  24. <aop:after-throwing method="exception" pointcut-ref="userSetName"/>
  25. </aop:aspect>
  26. </aop:config>
  27. </beans>
  28. </beans>

aspectj表达式的写法中,可以用*代替方法名、类名、包名等

注解相关

xml+注解形式

  1. package com.wangzhi.util;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.stereotype.Component;
  7. @Component
  8. @Aspect
  9. public class AopUtils {
  10. @Pointcut("execution(public void com.wangzhi.domain.User.*(..))")
  11. public void aopMethod() {
  12. }
  13. @Before("aopMethod()")
  14. public void before(JoinPoint joinPoint) {
  15. Object[] args = joinPoint.getArgs();
  16. for (Object arg : args) {
  17. System.out.println("前置通知的参数为:" + arg);
  18. }
  19. System.out.println("前置通知结束");
  20. }
  21. @AfterReturning(value = "aopMethod()", returning = "value")
  22. public void after(String value) {
  23. System.out.println("后置通知结束");
  24. }
  25. @AfterThrowing("aopMethod()")
  26. public void exception(JoinPoint joinPoint) {
  27. System.out.println("异常通知结束");
  28. }
  29. @After("aopMethod()")
  30. public void finallyAdvice() {
  31. System.out.println("最终通知");
  32. }
  33. @Around("aopMethod()")
  34. public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  35. System.out.println("环绕通知前置");
  36. proceedingJoinPoint.proceed();
  37. System.out.println("环绕通知后置");
  38. }
  39. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans default-lazy-init="false" xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. https://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/aop
  11. https://www.springframework.org/schema/aop/spring-aop.xsd">
  12. <beans>
  13. <aop:aspectj-autoproxy proxy-target-class="true"/>
  14. </beans>
  15. </beans>

纯注解

其实就是将注解驱动和代理设置放在配置Bean上,使用的注解为: @EnableAspectJAutoProxy

源码追踪

AOP是通过代理实现的,所以我们要找到的是创建代理Bean的代码,看看是怎么的一个流程,那就需要看一下我们创建Bean的方法,也就是refresh中的finishBeanFactoryInitialization(beanFactory)

  • DefaultListableBeanFactory#preInstantiateSingletons
  • AbstractBeanFactory#getBean(java.lang.String)
  • AbstractBeanFactory#doGetBean
  • AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
  • AbstractAutoProxyCreator#postProcessAfterInitialization
  • AbstractAutoProxyCreator#wrapIfNecessary
  • AbstractAutoProxyCreator#createProxy
  • ProxyFactory#getProxy(java.lang.ClassLoader)

    1. public Object getProxy(@Nullable ClassLoader classLoader) {
    2. return createAopProxy().getProxy(classLoader);
    3. }
  • CglibAopProxy#getProxy(java.lang.ClassLoader)

当然也可能是JDK的动态代理,这个就看具体的配置了,知道两个代理的区别:jdk的动态代理必须要有接口的实现就可以了。

总结就是其实是依赖于Bean的后置处理器来完成反射对象的创建。