最近工作不太忙,把spring aop又重新看了一遍,今天做下笔记,方便以后查看。
aop众所周知,是面向切面编程。具体的条条框框概念这里就不说了,百度一大堆。
通俗的来讲就是:对我们期望的一个切点面上的所有地方进行统一的操作。
首先需要spring的一些基础的jar包,当然包括aop及其所依赖的jar
接着我们需要编写一个类,也就是我例子中的MyAspect
package org.vic.aop.aspect; import org.aspectj.lang.ProceedingJoinPoint; public class MyAspect { public void printBeginning(){ System.out.println("hello everyone !"); } public void printEnd(){ System.out.println("thank you!"); } public void printSorry(){ System.out.println("I'm sorry,I'm too old..."); } public void printAround(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("weng weng weng..."); pjp.proceed(); System.out.println("weng weng ..."); } }
这个类是干嘛的呢?
该类其实就是写了aop要做的事情,什么时候做是在aop配置代码中展现的,后面会说。
接着是一个service接口及其实现类,里面有一个方法:
package org.vic.aop.service; public interface IMyIntroductionService { public void doIntroduce(String name,int age); }
package org.vic.aop.service.impl; import org.vic.aop.service.IMyIntroductionService; public class MyIntroductionServiceImpl implements IMyIntroductionService { @Override public void doIntroduce(String name, int age) { //if(age>15){ // throw new IllegalArgumentException(); //} System.out.println("I'm "+name+" I'm "+age); } }
接着写一个controller测试用:
package org.vic.aop.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.vic.aop.service.IMyIntroductionService; @Controller @RequestMapping("/test") public class TestController { private IMyIntroductionService myIntroductionService; @RequestMapping("/doTest") public void doTest(String name,int age){ myIntroductionService.doIntroduce(name, age); } public void setMyIntroductionService( IMyIntroductionService myIntroductionService) { this.myIntroductionService = myIntroductionService; } }
代码搞定,接下来开始配置aop:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" > <!-- 激活spring的注解. --> <context:annotation-config /> <!-- 扫描注解组件并且自动的注入spring beans中. 例如,他会扫描@Controller 和@Service下的文件.所以确保此base-package设置正确. --> <context:component-scan base-package="org.vic.aop" /> <!-- 配置注解驱动的Spring MVC Controller 的编程模型.注:次标签只在 Servlet MVC工作! --> <mvc:annotation-driven /> <bean id="myIntroductionService" class="org.vic.aop.service.impl.MyIntroductionServiceImpl" /> <bean id="myAspect" class="org.vic.aop.aspect.MyAspect"/> <bean id="testController" class="org.vic.aop.controller.TestController"> <property name="myIntroductionService" ref="myIntroductionService"/> </bean> <aop:config> <aop:aspect id="aopAspect" ref="myAspect"> <!--配置com.spring.service包下所有类或接口的所有方法--> <aop:pointcut id="myPoint" expression="execution(* org.vic.aop.service.*.*(..))" /> <aop:before pointcut-ref="myPoint" method="printBeginning"/> <aop:after pointcut-ref="myPoint" method="printEnd"/> <aop:around pointcut-ref="myPoint" method="printAround"/> <aop:after-throwing pointcut-ref="myPoint" method="printSorry" throwing="ex"/> </aop:aspect> </aop:config> </beans>
配置aop,首先要配置aspect 也就是 我们的MyAspect类
接着配置poincut,用表达式来说明路径下哪个包下的class文件在执行的时候会被aop影响。
这里我们配置了service包下的class
再下来就是重点的了:
before:pointcut-ref="myPoint" 表示当前的before配置是生效于我们的pointcut配置的,凡是service下面的方法被执行时都会先执行我们的before方法对应的method ---> printBeginning
(以上说明对下面的配置同理)
after: 看字面意思也明白了,就是在pointcut中包含的放法执行之后会执行after对应的method---> printEnd
只配置这两项的话打印的内容为:
请求url为:http://127.0.0.1:8080/SpringAOPTest/test/doTest?name=zhangsan&age=11
hello everyone !
I'm zhangsan I'm 11
thank you!
我们看到我们的service实现类的实现方法其实只打印了 I'm zhangsan I'm 11。但由于配置了aop 所以执行了MyAspect中的printBeginning方法(之前),printEnd方法(之后)。
接着配置--------------------------------------------------------------------------
around:此配置项对应的method会包围着被调用的service方法执行,优先级(开始优先级)小于begin配置,但结束优先级大于after配置。
after-throwing:如果被执行的service方法出现了异常> 放开service方法中的注释
:
if(age>15){ throw new IllegalArgumentException(); }
如果传入的age>15直接抛出异常。那么如果有异常抛出时就会执行该配置对应的方法。
我们现在将此处代码注释放开,并将aop配置内容全部配置。来看看结果:
请求url:http://127.0.0.1:8080/SpringAOPTest/test/doTest?name=zhangsan&age=11
传入age小于15 不会抛出异常,结果:
hello everyone !
weng weng weng...
I'm zhangsan I'm 11
thank you!
weng weng ...
以上结果就验证了around配置的特点。一直执行了printEnd方法后(thank you!)后才执行了around对应方法中的最后一句。
请求url:http://127.0.0.1:8080/SpringAOPTest/test/doTest?name=zhangsan&age=17
本次请求会抛出异常,因为age>15
结果为:
hello everyone !
weng weng weng...
thank you!
I'm sorry,I'm too old...
严重: Servlet.service() for servlet [MVCServlet] in context with path [/SpringAOPTest] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException] with root cause
java.lang.IllegalArgumentException....
以上结果执行了
after-throwing对应方法中的打印,也就是:I'm sorry,I'm too old...
从结果可以看出:先执行before
接着去执行around
再去执行service方法,但是它抛出异常了,没有执行到打印语句就已经跳出了。
atfer对应的method依然会被执行。
最后执行了我们配置的after-throwing对应的method,之后控制台才打印出来异常信息。
附件有测试学习的包,方便快速上手。
为了更全面的学习配置,我从别人博客里扒了点东西:
《Spring参考手册》中定义了以下几个AOP的重要概念,结合以上代码分析如下:
- 切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”,在本例中,“切面”就是类TestAspect所关注的具体行为,例如,AServiceImpl.barA()的调用就是切面TestAspect所关注的行为之一。“切面”在ApplicationContext中<aop:aspect>来配置。
- 连接点(Joinpoint) :程序执行过程中的某一行为,例如,AServiceImpl.barA()的调用或者BServiceImpl.barB(String _msg, int _type)抛出异常等行为。
- 通知(Advice) :“切面”对于某个“连接点”所产生的动作,例如,TestAspect中对com.spring.service包下所有类的方法进行日志记录的动作就是一个Advice。其中,一个“切面”可以包含多个“Advice”,例如TestAspect
- 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。例如,TestAspect中的所有通知所关注的连接点,都由切入点表达式execution(* com.spring.service.*.*(..))来决定
- 目标对象(Target Object) :被一个或者多个切面所通知的对象。例如,AServcieImpl和BServiceImpl,当然在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象。
-
AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,例如,AServiceImpl;反之,采用CGLIB代理,例如,BServiceImpl。强制使用CGLIB代理需要将
<aop:config>
的proxy-target-class
属性设为true
通知(Advice)类型
- 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。例如,TestAspect中的doBefore方法
- 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。例如,TestAspect中的doAfter方法,所以AOPTest中调用BServiceImpl.barB抛出异常时,doAfter方法仍然执行
- 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在<aop:aspect>里面使用<after-returning>元素进行声明。
- 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。例如,TestAspect中的doAround方法。
- 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。例如,TestAspect中的doThrowing方法。
切入点表达式
- 通常情况下,表达式中使用”execution“就可以满足大部分的要求。表达式格式如下:
相关推荐
一、 开始使用annotation配置Spring 16 二、 @Autowired、@Qualifier 16 (一) @Autowired 16 (二) @Qualifier 17 三、 @Resource(重要、推荐) 17 (一) JSR-250 17 (二) @Resource 17 四、 @Componet 18 五、 @Scope...
内容概要:学习Spring的一些学习笔记,主要学习Spring 框架两大核心机制(IoC、AOP) 笔记大纲:阅读笔记可以学习了解一下内容 如何使用 IoC ;配置文件;IoC 底层原理;通过运行时类获取 bean;通过有参构造创建 ...
"spring课堂笔记.docx" 是一份详尽的学习材料,旨在帮助开发者掌握 Spring 框架的核心概念和用法。Spring 框架是一个广泛用于构建企业级 Java 应用程序的开源框架,它提供了许多功能和工具,以简化开发过程并提高...
一、 开始使用annotation配置Spring 16 二、 @Autowired、@Qualifier 16 (一) @Autowired 16 (二) @Qualifier 17 三、 @Resource(重要、推荐) 17 (一) JSR-250 17 (二) @Resource 17 四、 @Componet 18 五、 @Scope...
- 比如有一个类,在类里面有方法(不是静态的方法),调用类里面的方法,创建类的对象,使用对象调用方法,创建类对象的过程,需要new出来对象 - 把对象的创建不是通过new方式实现,而是交给spring配置创建类对象 3...
对于bean的理解,希望大家是把他看成Object对象,他可以是任何对象,甚至是接口,甚至是抽象方法,当然,具体用法大家在以后的使用中会有所认识的; 写一个简单的bean类 ```java package mybatis.study.start.bean...
SSH笔记-包含使用动态代理的方法解决代码混乱、分散问题+基于注解方式配置AOP通知+用基于 XML 的配置声明切面
首先我们应该想想为什么要使用aop面向切面编程?面向切面的底层实现是什么?小编在这里举个例子吧 小编首先给出Spring全家桶,方便大家下载使用—->Spring全家桶 1.自定义代理对象代理类以及实现类 1.1 定义接口...
springboot学习笔记 spring基础 Spring概述 Spring的简史 xml配置 注解配置 java配置 Spring概述 Spring的模块 核心容器CoreContainer Spring-Core Spring-Beans ...
Spring的Ioc Spring的AOP , AspectJ Spring的事务管理 , 三大框架的整合 目录 1.1 Spring 框架学习路线:..........................................................................................................
- immutables:展示了使用Immutables的Spring Data JDBC用法。 4. Spring Data JPA: - eclipselink:展示了如何在Spring Boot和Eclipselink中使用Spring Data JPA的示例项目。 - example:包含了各种示例包,...
其他项目:Spring Cloud微服务学习笔记 Spring Boot项目实践 Java体系知识点汇总: : 网站资源链接 S3基本使用事件 数据库隔离等级验证 常用JVM命令验证 AOP实用技巧;某些打日志等 m3u解析器 知识汇总::::...
个人总结: 容器的实现 属性名解析相关类 AOP相关接口 SpringMVC 容器的使用
其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细...
奥普如果您正在阅读此文件,也许您正在搜索有关此存储库中包含的代码的信息:该代码代表原型、有趣的* AOP 引擎的核心,该引擎实现的机制类似于 SpringFramework 实现的方法代理机制; 这种行为是通过代理类的运行时...
spring 框架是一个开源而轻量级的框架,是一个 IOC 和 AOP 容器,spring 的核心就是控制反转(IOC)和面向切面编程(AOP) 控制反转(IOC):是面向对象编程中的一种设计原则,用来降低程序代码之间的耦合度,使...
{1.7}方法}{26}{section.1.7} {1.8}运算符}{27}{section.1.8} {1.8.1}自增运算}{28}{subsection.1.8.1} {1.8.1.1}Postincrement}{28}{subsubsection.1.8.1.1} {1.8.1.2}Preincrement}{28}{subsubsection.1.8....
使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法 制作一个简单的多页Tab功能 一完美的关于请求的目录不存在而需要url重写的解决方案! 在C#中实现MSN消息框的功能 XmlHttp实现无刷新三联动ListBox 鼠标...