Spring 笔记(三)
AOP: Aspect Oriented Programing 面向切面编程
使用动态代理实现AOP
传统方法:
- 基于接口的动态代理:Proxy.newProxyInstance
- 基于子类的动态代理:Enhancer.create
术语:
- JoinPoint(连接点):所代理类的所有方法。
- Pointcut(切入点):被增强的方法是切入点。
- Advice(通知/增强):拦截到JoinPoint之后要做的事情。
- 前置通知
- 事务前
- 后置通知
- 事务后
- 异常通知
- catch中
- 最终通知
- finally中
- 环绕通知
- 整个invoke
- 前置通知
- Target(目标对象\被代理对象)
- Introduction(引介):特殊的通知
- Weaving(织入):根据目标对象创建代理对象的过程
- Proxy(代理):织入增强后产生的代理类
- Aspect(切面):切入点和通知的结合
基于Spring的AOP编程
基于XML的AOP
配置XML文件
<bean id="logger" class="xyz.aiinirii.spring.utils.Logger"/>
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<!-- 类比在事务之前所做的事情 -->
<aop:before method="beforePrintLog"
pointcut="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<!-- 类比在事务成功之后所做的事情 例如 commit -->
<aop:after-returning method="afterReturningPrintLog"
pointcut="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<!-- 例如回滚 -->
<aop:after-throwing method="afterThrowingPrintLog"
pointcut="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<!-- 例如关闭链接 -->
<aop:after method="afterPrintLog"
pointcut="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
</aop:aspect>
</aop:config>
运行效果,saveAccount方法得到了增强:

或者这样:
<bean id="logger" class="xyz.aiinirii.spring.utils.Logger"/>
<aop:config>
<aop:pointcut id="serviceImpl" expression="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="beforePrintLog"
pointcut-ref="serviceImpl"/>
<aop:after-returning method="afterReturningPrintLog"
pointcut-ref="serviceImpl"/>
<aop:after-throwing method="afterThrowingPrintLog"
pointcut-ref="serviceImpl"/>
<aop:after method="afterPrintLog"
pointcut-ref="serviceImpl"/>
</aop:aspect>
</aop:config>
环绕通知?
<bean id="logger" class="xyz.aiinirii.spring.utils.Logger"/>
<aop:config>
<aop:pointcut id="serviceImpl" expression="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<aop:aspect id="logAdvice" ref="logger">
<aop:around method="aroundPrintLog" pointcut-ref="serviceImpl"/>
</aop:aspect>
</aop:config>

发现并没有执行被增强的函数。切入点方法没有执行,而通知方法执行了。
原因分析:并没有在环绕通知中调用切入点方法。
public Object aroundPrintLog(ProceedingJoinPoint joinPoint){
Object rtValue = null;
try {
System.out.println("Before Print Log...");
rtValue = joinPoint.proceed();
System.out.println("After Return Print Log...");
} catch (Throwable throwable) {
System.out.println("After Throwing Print Log...");
throwable.printStackTrace();
} finally {
System.out.println("After Print Log...");
}
return rtValue;
}
<bean id="logger" class="xyz.aiinirii.spring.utils.Logger"/>
<aop:config>
<aop:pointcut id="serviceImpl" expression="execution(* xyz.aiinirii.spring.service.impl.*.*(..))"/>
<aop:aspect id="logAdvice" ref="logger">
<aop:around method="aroundPrintLog" pointcut-ref="serviceImpl"/>
</aop:aspect>
</aop:config>
基于注解的AOP
<aop:aspectj-autoproxy/>
Logger 类,通知类:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author AIINIRII
*/
@Component("logger")
@Aspect
public class Logger {
@Before("execution(* xyz.aiinirii.spring.service.impl.*.*(..))")
public void beforePrintLog() {
System.out.println("Before Print Log...");
}
@AfterReturning("execution(* xyz.aiinirii.spring.service.impl.*.*(..))")
public void afterReturningPrintLog() {
System.out.println("After Return Print Log...");
}
@AfterThrowing("execution(* xyz.aiinirii.spring.service.impl.*.*(..))")
public void afterThrowingPrintLog() {
System.out.println("After Throwing Print Log...");
}
@After("execution(* xyz.aiinirii.spring.service.impl.*.*(..))")
public void afterPrintLog() {
System.out.println("After Print Log...");
}
// @Around("execution(* xyz.aiinirii.spring.service.impl.*.*(..))")
public Object aroundPrintLog(ProceedingJoinPoint joinPoint){
Object rtValue = null;
try {
System.out.println("Before Print Log...");
rtValue = joinPoint.proceed();
System.out.println("After Return Print Log...");
} catch (Throwable throwable) {
System.out.println("After Throwing Print Log...");
throwable.printStackTrace();
} finally {
System.out.println("After Print Log...");
}
return rtValue;
}
}
AccountServiceImpl 类,Target 类:
import org.springframework.stereotype.Service;
import xyz.aiinirii.spring.service.IAccountService;
/**
* @author AIINIRII
*/
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
public void saveAccount() {
System.out.println("Successfully save the account.");
}
}
总结
提取重复代码:arrow_right:创建代理对象
从而实现AOP
提示,尽量用@Around()否则最终和异常/后置顺序将会出错。