[Spring]AOP基础
来源:互联网 发布:js添加图片二维数组 编辑:程序博客网 时间:2024/05/16 08:51
- 背景问题
- AOP简介
- AOP术语
- 用AspectJ注解声明切面
- 前置通知
- 后置通知
- 返回通知
- 异常通知
- 环绕通知
- 引入通知较少使用
- 切面的优先级
- 重用切点表达式
- 基于配置文件配置AOP
背景问题
- 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀.每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点
- 代码分散:以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志打印代码.如果日志需求发生变化,必须修改所有模块
AOP简介
- AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充
- AOP的主要编程对象是切面(aspect),而切面模块化横切关注点
- 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类.这样一来横切关注点就被模块化到特殊的对象(切面)里.
- AOP的好处:
- 每个事物逻辑位于一个位置,代码不分散,便于维护和升级
- 业务模块更简洁,只包含核心业务代码
AOP术语
- 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
- 通知(Advice):切面必须要完成的工作
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如ArithmethicCalculator#add()方法执行前的连接点,执行点为ArithmethicCalculator#add();方位为该方法执行前的位置
- 切点(pointcut):每个类都拥有多个连接点:例如ArithmethicCalculator的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件
用AspectJ注解声明切面
- 要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为Bean实例.当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那么与AspectJ切面相匹配的Bean创建代理
- 在AspectJ注解中,切面只是一个带有@Aspect注解的Java类
- 通知是标注有某种注解的简单的Java方法
- AspectJ支持5中类型的通知注解:
- @Before:前置通知,在方法执行之前执行
- @After:后置通知,在方法执行之后执行
- @AfterRunning:返回通知,在方法返回结果之后执行
- @AfterThrowing:异常通知,在方法抛出异常之后执行
- @Around:环绕通知,围绕着方法执行
前置通知
- @Before(“execution(方法路径)”)
- AspectJ:Java社区里最完整最流行的AOP框架,在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP
- 在Spring中启用AspectJ注解支持:
1. 要在Spring应用中使用AspectJ注解,必须在classpath下包含AspectJ类库:aoplliance.jar、aspectj.weaver.jar和spring-aspects.jar
2. 将aopSchema添加到<beans>
根元素中.
3. 要在SpringIOC容器中启用AspectJ注解支持,只要在Bean配置文件中定义一个空的XML元素<aop:aspectj-autoproxy>
4. 当Spring IOC容器侦测到Bean配置文件中的<aop:aspectj-autoproxy>
元素时,会自动为与AspectJ切面匹配的Bean创建代理
/声明该方法是一个前置通知:在目标方法开始前执行/
@Before("execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))")public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method is begining"); System.out.println("The method is " + methodName + " and args are " + args);}
后置通知
// 声明该方法是一个后置通知:在目标方法结束后执行(无论是否发生异常)// 在后置通知中不能访问目标方法执行的结果@After("execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))")public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method is end"); System.out.println("The method is " + methodName + " and args are " + args);}
返回通知
// 声明该方法是一个返回通知:在目标方法正常结束后执行// 在返回通知中可以访问目标方法执行的结果@AfterReturning(value = "execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))", returning = "result")public void afterReturnMethod(Object result){ System.out.println("The method is end"); System.out.println("The result is " + result);}
异常通知
// 声明该方法是一个异常通知:在目标方法抛出异常后执行@AfterThrowing(value = "execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))", throwing = "exception")public void afterThrowMethod(NullPointerException exception){ System.out.println("The method throwing exception "); System.out.println("The exception is " + exception);}*/
环绕通知
// 声明该方法是一个环绕通知,需要携带ProceedingJoinPoint类型的参数// 环绕通知类似于动态代理的全过程;ProceedingJoinPoint类型的参数可以决定是否执行目标方法// 且环绕通知必须有返回值,返回值即为目标方法的返回值@Around("execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))")public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ Object result = null; String methodName = proceedingJoinPoint.getSignature().getName(); // 执行目标方法 try{ // 前置通知 System.out.println("The method:" + methodName + " begings with:" + Arrays.asList(proceedingJoinPoint.getArgs())); result = proceedingJoinPoint.proceed(); System.out.println("The result is:" + result); } catch (Throwable throwable) { System.out.println("异常通知"); throwable.printStackTrace(); } // 后置通知 System.out.println("The method is ended"); return result;}
引入通知(较少使用)
引入通知是一种特殊的通知类型。它通过为接口提供实现类,允许对象动态的实现接口,就像对象已经在运行时扩展了实现类一样
切面的优先级
使用@Order类注解指定优先级,值越小优先级越高如@Order(2)
重用切点表达式
可以定义一个方法,用于声明切入点表达式.一般地,该方法中不再需要填入其他的代码,例如:
在切面类中定义方法:
//使用@Pointcut来声明切入点表达式,其他通知直接使用方法名来引用当前的切入点表达式@Pointcut("execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))")public void declareJointPointExpression(){}
然后,上面前置通知、后置通知…使用引用“execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))”的地方可以替换为declareJointPointExpression(),如果是在其他类(包)中引用,需要带上类名(及包名)
基于配置文件配置AOP
- 先在配置文件中配置bean
- 配置AOP:
//<!-- 配置AOP --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(public int spring_aop.ArithmeticCalculatorImpl.*(String))" id="pointcut"> <!-- 配置切面及通知--> <aop:aspect ref="切面bean的id" order="2"> <aop:before method="beforeMethod" pointcut-ref="pointcut"> </aop:aspect> </aop:config>
阅读全文
0 0
- spring aop 基础
- Spring Aop基础使用
- Spring AOP---基础简介
- Spring AOP基础
- Spring Aop基础总结
- Spring AOP基础
- spring aop基础概念
- Spring AOP基础
- Spring中AOP基础
- Spring中的AOP基础
- SpringBoot2-spring基础-AOP
- Spring Aop基础
- Spring AOP 基础
- spring aop基础
- Spring基础-3-AOP
- Spring AOP基础
- Spring基础入门AOP
- [Spring]AOP基础
- ELK 安装配置中的默认端口结构图
- Shuffle UVA
- 欢迎使用CSDN-markdown编辑器
- 8.1.3 字符串与基本数据的相互转化
- Python特殊语法:filter、map、reduce、lambda
- [Spring]AOP基础
- 黄金分割点问题
- 一个简单的投票
- MySQL数据库优化的八种方式(经典必看)
- 数据结构专题训练及总结
- Redis主从复制和集群实验
- TextView设置跑马灯效果
- css 图片自使用界面变化
- 总结