Aop概念
,Aspect Oriented Programming的缩写,意为:面向切面编程
spring aop怎么用
用法:AOP主要包含了通知、切点和连接点等术语
- 通知:通知定义了切面什么以及何时调用,
如before(在方法调用之前调用通知),
after(在方法完成之后调用通知,无论方法执行是否成功),
after-retuning(在方法成功执行之后调用通知),
after-throwing(在方法抛出异常后调用通知),
around(通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为) - 切点:通知定义了切面是什么和何时,切点定义了何处,切点的定义会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。
切点的格式如下
execution(* com.ganji.demo.service.user.UserService.GetDemoUser (..) )
- 连接点(JoinPoint)
连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,甚至是修改一个字段时,切面代码可以利用这些连接点插入到应用的正常流程中,并添加新的行为,如日志、安全、事务、缓存等。
用法:
同依赖注入一样,AOP在spring中有两种配置方式,
一是xml配置的方式,二是自动注解的模式。
<!--定义切面 指定拦截方法时 做什么-->
<bean id="xmlAopDemoUserLog" class="com.ganji.demo.service.aspect.XmlAopDemoUserLog"></bean>
<aop:config>
<aop:aspect ref="xmlAopDemoUserLog">
<!--指定切面--> <!--定义切点-->
<aop:pointcut id="logpoint" expression="execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..))">
</aop:pointcut>
<!--定义连接点-->
<aop:before pointcut-ref="logpoint" method="beforeLog"></aop:before>
<aop:after pointcut-ref="logpoint" method="afterLog"></aop:after>
<aop:after-returning pointcut-ref="logpoint" method="afterReturningLog"></aop:after-returning>
<aop:after-throwing pointcut-ref="logpoint" method="afterThrowingLog"></aop:after-throwing>
</aop:aspect>
</aop:config>
小结
Xml形式:首先定义切面要做的事情,
再定义一个切面,引用这个要做事情的bean
再定义一个切点,要在哪些地方织入切面(正则表达式)
再定义连接点,即要引用切面中的哪个方法
使用配置注解
首先我们要将切面在spring上下文中声明成自动代理bean,我们需要在web层的web-inf/dispatcher-servlet.xml文件中配置如下一句话即可
<aop:aspectj-autoproxy />
当然我们需要在xml的根目录beans下引用aop的命名空间和xsi
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
@Aspect
@Service
public class XmlAopDemoUserLog {
// 配置切点 及要传的参数
@Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)")
public void pointCut(int id) {
}
// 配置连接点 方法开始执行时通知
@Before("pointCut(id)")
public void beforeLog(int id) {
System.out.println("开始执行前置通知 日志记录:" + id);
}
}
// 方法执行完后通知
@After("pointCut(id)")
public void afterLog(int id) {
System.out.println("开始执行后置通知 日志记录:" + id);
}
// 执行成功后通知
@AfterReturning("pointCut(id)")
public void afterReturningLog(int id) {
System.out.println("方法成功执行后通知 日志记录:" + id);
}
// 抛出异常后通知
@AfterThrowing("pointCut(id)")
public void afterThrowingLog(int id) {
System.out.println("方法抛出异常后执行通知 日志记录" + id);
}
// 环绕通知
@Around("pointCut(id)")
public Object aroundLog(ProceedingJoinPoint joinpoint, int id) {
Object result = null;
try {
System.out.println("环绕通知开始 日志记录" + id);
}
long start = System.currentTimeMillis();
//有返回参数 则需返回值
result = joinpoint.proceed();
long end = System.currentTimeMillis();
System.out.println("总共执行时长" + (end - start) + " 毫秒");
System.out.println("环绕通知结束 日志记录");
} catch(Throwable t){
System.out.println("出现错误");}
return result;}
}
怎么实现
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。