AOP,Aspect Oriented Programming,面向切面编程,spring中只能拦截bean的方法,不能拦截类。基本思路是将方法内互不相交的业务逻辑分离并单独开发,最后通过动态代理实现各业务逻辑的组合。
关注点,业务上不可继续分割的最小组件。
关注点分离,将功能模块划分成若干业务上不可继续分割的最小组件。
横切关注点,将功能模块化分成若干最小组件后,辅助组件会以横切的形式与核心组件组合,辅助组件为横切关注点。
植入,横切关注点以横切的形式与关注点组合的过程,根据目标对象生成代理对象的过程。
连接点,jointpoint,被切入的方法。
切入点,pointcut,项目中可能有很多方法需要横切同一个功能,所有这些方法的集合称为切入点。
通知,advice,要切入到连接点的具体内容。
切面,aspect,切入点与通知的组合。
<beans>
// ====================xml方式
// 注册通知
<bean id="xxAdvice" class="..XxAdvice" />
// 配置aop
<aop:config>
// expression用于配置切入点表达式,多个表达式可用and、or、!或&&、||、!连接
// execution(方法表达式)表达式,within(类型表达式),this(类全名),target(类全名)
<aop:pointcut id="xxPointcut" expression="execution(* xx.service.impl.*.*(..))
or execution(* xx.service.impl.*.*(..))
or .." />
// 配置切面
<aop:aspect ref="xxAdvice">
// 在拦截方法前执行通知
<aop:before method="doBefore" pointcut-ref="xxPointcut" />
// 在拦截方法后执行通知
<aop:after method="doAfter" pointcut-ref="xxPointcut" />
// 不再执行原方法,直接执行通知,根据需求,通知内可调用原方法
<aop:around method="doAround" pointcut-ref="xxPointcut" />
</aop:aspect>
</aop:config>
// ====================注解方式
<context:component-scan base-package="..*" />
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
@Component("xxAdvice")
public class XxAdvice {
// 空方法,只为生成切入点,注解Pointcut配置要拦截或被切入的方法
// 第一个*表示方法的返回类型为任意,xx.service.impl.*表示xx.service.impl包下的任意类
// xx.service.impl..*表示xx.service.impl包及其子包下的任意类,*(..)表示任意方法,方法参数的个数、类型为任意
// *(*, int)表示任意方法,方法的参数为两个,第一个任意类型,第二个int类型
@Pointcut("execution(* xx.service.impl.*.*(..))")
private void xxPointcut() {}
// 注解配置前置通知
@Before("xxPointcut()")
public void doBefore() {}
// 注解配置后置通知
@After("xxPointcut()")
public void doAfter() {}
// 注解配置环绕通知,会阻止原方法,但切面内部可自行执行核心方法
@Around("xxPointcut()")
public Object doAround(ProceedingJoinPoint pjp) {
Object obj = null;
before:原方法执行前切面
原方法:obj = pjp.proceed();
after:原方法执行后切面
// 切记不要忘记返回
return obj;
}
}