[关闭]
@ghimi 2018-08-02T07:23:08.000000Z 字数 4526 阅读 933

Spring AOP学习笔记

spring


1. 介绍

AOP : 面向切面编程,相对于OOP面向对象编程.
Spring 的 AOP 的存在目的是为了解耦.AOP可以让一组类共享相同的行为.在OOP中只能通过继承类和实现接口,来时代码的耦合度增强,且类继承只能为单继承,阻止了更多的类添加到一组类上,AOP弥补了OOP的不足.
Spring 支持 AspectJ 的注解是切面编程.
1. 使用@Aspect 声明是一个切面.
2. 使用@After,@Before,@Around 定义建言(advice),可直接将拦截规则(切点作为参数).
3. 其中@After,@Before,@Around 参数的拦截规则为切点(PointCut),为了是切点复用,可使用@PointCut 专门定义拦截规则,然后再@After,@Before,@Around 的参数中调用,
4. 其中符合条件的每一个被拦截处为连接点(JoinPoint)
本节示例将演示基于注解拦截和基于方法规则拦截的两种方式,演示一种模拟记录操作的日志系统的实现.其中注解式拦截能够很好的控制要拦截的粒度和获得更丰富的信息,Spring本身在事务处理(@Transcational)和数据缓冲(@Cacheable等)上面都使用此种形式的拦截.

2. 使用注解实现AOP

2.1 首先编写注解类

  1. package spring4.ch1.aop;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Target(ElementType.METHOD)
  8. @Retention(RetentionPolicy.RUNTIME)
  9. //其实没有必要添加@Document的注解
  10. @Documented
  11. public @interface Action {
  12. String name();
  13. }

2.2 对需要拦截方法添加注解

  1. package spring4.ch1.aop;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. //对需要切入的方法上添加自定义的注解
  5. public class DemoAnnotationService {
  6. @Action(name="注解式拦截的add操作")
  7. public void add(){
  8. System.out.println("DemoAnnotation 类的add操作本身!");
  9. }
  10. @Factor(path = "Annotation from Factor and delete() method!")
  11. public void delete(){
  12. System.out.println("DemoAnnotation 类的delete操作本身");
  13. }
  14. }

3. 使用方法规则实现 AOP

3.1 直接编写类(不需要任何其他操作)

  1. package spring4.ch1.aop;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. //直接编写类,不需要其他任何操作
  5. public class DemoMethodService {
  6. public void add(){}
  7. }

4. AOP切面编写

在切面中,我们使用 @After@Before,将两种拦截切面都做了拦截

  1. package spring4.ch1.aop;
  2. import java.lang.reflect.Method;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.annotation.After;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Before;
  7. import org.aspectj.lang.annotation.Pointcut;
  8. import org.aspectj.lang.reflect.MethodSignature;
  9. import org.springframework.stereotype.Component;
  10. @Aspect
  11. @Component
  12. public class LogAspect {
  13. @Pointcut("@annotation(spring4.ch1.aop.Action)")
  14. public void annotationPointCut(){}
  15. @Pointcut("@annotation(spring4.ch1.aop.Factor)")
  16. public void annotationPointCut2(){}
  17. @Before("annotationPointCut()")
  18. public void after(JoinPoint joinPoint){
  19. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  20. Method method = signature.getMethod();
  21. Action action = method.getAnnotation(Action.class);
  22. System.out.println("注解式拦截 "+ action.name());
  23. }
  24. @Before("annotationPointCut2()")
  25. public void after2(JoinPoint joinPoint){
  26. MethodSignature signature = (MethodSignature)joinPoint.getSignature();
  27. Method method = signature.getMethod();
  28. Factor factor = method.getAnnotation(Factor.class);
  29. System.out.println("注解式拦截2 "+ factor.path());
  30. }
  31. @After("execution(* spring4.ch1.aop.DemoMethodService.*(..))")
  32. public void before(JoinPoint joinPoint) {
  33. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  34. Method method = signature.getMethod();
  35. System.out.println("方法规则式拦截, " + method.getName());
  36. }
  37. }
  1. 在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"
  2. 例如定义切入点表达式 execution(* com.sample.service.impl..*.*(..))
  3. execution()是最常用的切点函数,其语法如下所示:
  4. 整个表达式可以分为五个部分:
  5. 1execution(): 表达式主体。
  6. 2、第一个*号:表示返回类型,*号表示所有的类型。
  7. 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
  8. 4、第二个*号:表示类名,*号表示所有的类。
  9. 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

5. 测试代码

  1. package com.example.demo;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  6. import org.springframework.context.annotation.ComponentScan;
  7. import spring4.ch1.aop.DemoAnnotationService;
  8. import spring4.ch1.aop.DemoMethodService;
  9. import spring4.ch1.di.UseFunctionService;
  10. @SpringBootApplication
  11. @ComponentScan("spring4.ch1")
  12. @EnableAspectJAutoProxy
  13. //使用扫描注解方法建立context
  14. //然后执行我们的几个测试方法
  15. public class Demo1Application {
  16. public static void main(String[] args) {
  17. // ConfigurableApplicationContext run = SpringApplication.run(Demo1Application.class, args);
  18. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo1Application.class);
  19. String[] beanDefinitionNames = context.getBeanDefinitionNames();
  20. for (String string : beanDefinitionNames) {
  21. System.out.println(string);
  22. }
  23. UseFunctionService bean = context.getBean(UseFunctionService.class);
  24. // System.out.println(bean.sayHello("di"));
  25. DemoAnnotationService bean2 = context.getBean(DemoAnnotationService.class);
  26. DemoMethodService bean3 = context.getBean(DemoMethodService.class);
  27. bean3.add();
  28. bean2.add();
  29. bean2.delete();
  30. context.close();
  31. }
  32. }

测试结果输出

  1. 方法规则式拦截, add
  2. 注解式拦截 注解式拦截的add操作
  3. DemoAnnotation 类的add操作本身!
  4. 注解式拦截2 Annotation from Factor and delete() method!
  5. DemoAnnotation 类的delete操作本身
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注