AOP基于BeanPostProcessor实现。
Spring在初始化后会去判断当前正在创建的Bean是不是需要进行AOP 操作,如果需要则会进行动态代理。
AOP代理对象
生产代理类—>代理对象—>代理对象target赋值(target=普通对象
如何判断当前Bean对象是否需要进行AOP:

  1. 找出所有的切面Bean(使用@Aspect的Bean)【第一次解析后,会进行缓存】
  2. 遍历切面中的每个方法,看是否使用@Before、@After等注解。
  3. 如果使用,则逐个判断所对应的Pointcut是否和当前Bean对象的类是否匹配
  4. 如果匹配则表示当前Bean对象有匹配的的Pointcut,表示需要进行AOP,进行代理生成逻辑
  5. 把对应的代理方法(lambda表达)存放到三级缓存

https://note.youdao.com/ynoteshare/index.html?id=f30e818e00f2c3eb6d4f26e6c0b70ade&type=note&_time=1664262640199

一、基本介绍

Advice分类

  1. 1. Before Advice:方法之前执行。
  2. 1. @Before。会被解析为AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice
  3. 2. After returning advice:方法return后执行。
  4. 1. @AfterReturning。解析为:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice
  5. 3. After throwing advice:方法抛异常后执行。
  6. 1. @AfterThrowing。解析为AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor
  7. 4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后。
  8. 1. @After。解析为AspectJAfterAdvice,实际上就是一个MethodInterceptor
  9. 5. Around advice:功能最强大的Advice,可以自定义执行顺序。
  10. 1. @Around。解析为AspectJAroundAdvice,实际上就是一个MethodInterceptor

Advisor

与Advice类似。用于指定需要代理的方法
一个Advisor由一个Pointcut(负责指定增强方法)和一个Advice(负责增强逻辑)组成。Pointcut指定需要被代理的逻辑(方法)。如果不能指定,则代理类中的方法都会被代理。

  1. @Test
  2. public void advisorTest(){
  3. UserService target = new UserService();
  4. ProxyFactory proxyFactory = new ProxyFactory();
  5. proxyFactory.setTarget(target);
  6. proxyFactory.addAdvisor(new PointcutAdvisor() {
  7. //指定需要增强方法(logout)
  8. @Override
  9. public Pointcut getPointcut() {
  10. return new StaticMethodMatcherPointcut() {
  11. @Override
  12. public boolean matches(Method method, Class<?> targetClass) {
  13. return method.getName().equals("logout");
  14. }
  15. };
  16. }
  17. //定义增强逻辑
  18. @Override
  19. public Advice getAdvice() {
  20. return new org.aopalliance.intercept.MethodInterceptor() {
  21. @Override
  22. public Object invoke(MethodInvocation invocation) throws Throwable {
  23. System.out.println("before...");
  24. Object result = invocation.proceed();
  25. System.out.println("after...");
  26. return result;
  27. }
  28. };
  29. }
  30. @Override
  31. public boolean isPerInstance() {
  32. return false;
  33. }
  34. });
  35. ServiceInterface userService = (ServiceInterface) proxyFactory.getProxy();
  36. userService.login();
  37. userService.logout();
  38. }

通过Advisor指定在执行loginout方法时,才有执行增强逻辑。

AOP概念

  1. 1. Aspect:表示切面。被@Aspect注解的类就是切面,可以在切面中去定义PointcutAdvice
  2. 2. Join point:表示连接点,表示一个程序在执行过程中的一个点。在Spring AOP中,一个连接点通常表示一个方法的执行。
  3. 3. Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型。Spring使用拦截器(Interceptor)实现Advice,并且在连接点周围维护一个Interceptor
  4. 4. Pointcut:表示切点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上
  5. 5. Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现
  6. 6. Target object:目标对象,被代理对象
  7. 7. AOP proxy:表示代理工厂,用来创建代理对象的。在Spring Framework中,是JDK动态代理,或是CGLIB代理。
  8. 8. Weaving:表示织入,表示创建代理对象的动作,织入动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP

二、AOP实现由浅入深

1.利用Spring代理工厂完成逻辑增强

1.需要逐个指定代理对象。2.手动设置切入点

  1. @Configurable
  2. @ComponentScan("com.masterlu.ioc.aop")
  3. public class AopDemoConfig {
  4. @Bean
  5. public MethodInterceptor methodInterceptor() {
  6. return new MethodInterceptor() {
  7. @Override
  8. public Object invoke(MethodInvocation invocation) throws Throwable {
  9. System.out.println("before");
  10. Object proceed = invocation.proceed();
  11. System.out.println("after");
  12. return proceed;
  13. }
  14. };
  15. }
  16. @Bean
  17. public ProxyFactoryBean userService(){
  18. ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
  19. proxyFactoryBean.setTarget(new UserService());
  20. proxyFactoryBean.setInterceptorNames("methodInterceptor");
  21. return proxyFactoryBean;
  22. }
  23. }
  24. @Test
  25. public void springAOPTest1() {
  26. //因为UserService实现接口。所以产生JDK代理对象。只能使用接口类型
  27. ServiceInterface userService = (ServiceInterface) applicationContext.getBean("userService");
  28. userService.login();
  29. }

2.利用BeanNameAutoProxyCreator批量设置

需要手动设置切入点。

  1. @Configurable
  2. @ComponentScan("com.masterlu.ioc.aop")
  3. public class AopDemoConfig {
  4. @Bean
  5. public MethodInterceptor methodInterceptor() {
  6. return new MethodInterceptor() {
  7. @Override
  8. public Object invoke(MethodInvocation invocation) throws Throwable {
  9. System.out.println("before");
  10. Object proceed = invocation.proceed();
  11. System.out.println("after");
  12. return proceed;
  13. }
  14. };
  15. }
  16. @Bean
  17. public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
  18. BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
  19. beanNameAutoProxyCreator.setBeanNames("userSe*");
  20. beanNameAutoProxyCreator.setInterceptorNames("methodInterceptor");
  21. beanNameAutoProxyCreator.setProxyTargetClass(true);
  22. return beanNameAutoProxyCreator;
  23. }
  24. }

3.利用DefaultAdvisorAutoProxyCreator自动查找切入点

  1. @ComponentScan("com.masterlu.ioc.aop")
  2. public class AppConfig {
  3. //指定切入点以及增强逻辑。
  4. @Bean
  5. public DefaultPointcutAdvisor defaultPointcutAdvisor() {
  6. NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
  7. pointcut.addMethodName("login");
  8. DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
  9. defaultPointcutAdvisor.setPointcut(pointcut);
  10. defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
  11. @Override
  12. public void before(Method method, Object[] args, Object target) throws Throwable {
  13. method.invoke(target, args);
  14. }
  15. });
  16. return defaultPointcutAdvisor;
  17. }
  18. // DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例
  19. @Bean
  20. public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
  21. DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
  22. return defaultAdvisorAutoProxyCreator;
  23. }
  24. }

4.使用注解引入DefaultAdvisorAutoProxyCreator

  1. @ComponentScan("com.masterlu")
  2. //DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例
  3. @Import(DefaultAdvisorAutoProxyCreator.class)
  4. public class AppConfig {
  5. //指定切入点以及增强逻辑。
  6. @Bean
  7. public DefaultPointcutAdvisor defaultPointcutAdvisor() {
  8. NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
  9. pointcut.addMethodName("login");
  10. DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
  11. defaultPointcutAdvisor.setPointcut(pointcut);
  12. defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
  13. @Override
  14. public void before(Method method, Object[] args, Object target) throws Throwable {
  15. method.invoke(target, args);
  16. }
  17. });
  18. return defaultPointcutAdvisor;
  19. }
  20. }

DefaultPointcutAdvisor的功能可以使用注解(@Aspect、@Before、@After等注解)代替。
但是DefaultAdvisorAutoProxyCreator不能解析切面注解,需要使用AnnotationAwareAspectJAutoProxyCreator

5.利用注解设置注入点

  1. @Component
  2. @Aspect
  3. public class DemoAspect {
  4. @Pointcut("execution(* *.login(..))")
  5. public void login() {
  6. }
  7. }
  1. @ComponentScan("com.masterlu")
  2. @EnableAspectJAutoProxy
  3. public class AppConfig {
  4. }

@EnableAspectJAutoProxy(本质引入AnnotationAwareAspectJAutoProxyCreator)

切面逻辑中获取方法参数
image.png

三、代码

image.png