说明:
AOP:面向切面编程,通过预编译方式和运行期动态代理实现功能的一种技术,对业务各个部分隔离,降低耦合。
AspecjJ:AOP实现框架。
通用依赖jar包:commons-logging-x.x.jar、log4j-x.x.xx.jar
spring依赖jar包:spring-core-x.x.x.RELEASE.jar、spring-context-x.x.x.RELEASE.jar、spring-beans-x.x.x.RELEASE.jar、spring-expression-x.x.x.RELEASE.jar、spring-aop-x.x.x.RELEASE.jar、spring-aspects-x.x.x.RELEASE.jar
AspecjJ依赖jar包:aspectjweaver-x.x.x.jar、aopalliance-x.x.jar
术语:
Joinpoint:连接点,可以被拦截的点(方法)。
Pointcut:切入点,真正被拦截的点(方法)。
Advice:通知、增强,方法层面的,对方法进行权限校验,权限校验的方法就是通知。
通知分类:
前置通知:在目标方法前执行。
后置通知(返回通知):在目标方法后执行。
环绕通知:在目标方法前与后都执行。
异常抛出通知:出现异常时执行。
最终通知:不管是否出现异常,总是执行。
引介通知:目标类能同时继承多个实现类
Introduction:引介,类层面的增强
Target:被增加的对象
Weaving:织入,将通知应用到目标对象方法的过程
Proxy:代理对象
Aspect:切面,多个通知+多个切入点组合的统称
一、xml方式,配置切面类、通知方法:
1.创建自定义切面类:
//自定义切面类
public class XmlAspecjJ {
// 在目标方法前执行
public void onInsertBefore() {}
// 在目标方法后执行
public void onInsertAfter() {}
//在目标方法前与后都执行
public void onInsertBeforeAndAfter() {}
//出现异常时执行, 参数名t要和<aop:after-throwing>节点throwing值一致
public void onInsertException(Throwable t) {}
//不管是否出现异常,总是执行
public void onFinally() {}
}
2.配置切面类,在applicationContext.xml的<beans>节点内配置:
(1)<aop:pointcut>节点的expression属性值说明:
格式:
execution(返回值 包名.类名.方法名(参数列表))
例:
execution(* com.yyh.hkw.dao.*Dao.*(..))
解释:
*表示任意字符或类型
除了参数必须用“..”或具体类型,其他都可以用*表示
第1个*指返回值类型可以任意值
第2个*指以Dao结尾的类
第3个*指任意方法
..指任意参数
(2)配置切面类,使用<aop:config>节点:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 让spring创建对象 -->
<bean id="userDao" class="com.yyh.hkw.dao.UserDao"/>
<!-- 一、让spring创建XmlAspecjJ自定义对象 -->
<bean id="xmlAspecjJ" class="com.yyh.hkw.dao.XmlAspecjJ" />
<!-- 二、配置XmlAspecjJ为切面类 -->
<aop:config>
<!-- 1.配置表达式,哪个类哪个方法需要增强,这里增强UserDao类的insert方法;第1* 表示任意返回值,..表示方法有任意个参数;id为引用名,供后面使用 -->
<aop:pointcut expression="execution(* com.yyh.hkw.dao.UserDao.insert(..))" id="pointcutId" />
<!-- 2.配置切面类,xmlAspecjJ为<bean>节点id的值 -->
<aop:aspect ref="xmlAspecjJ">
<!-- (1)配置前置通知,在目标方法前执行,onInsertBefore为 XmlAspecjJ类中自定义方法。pointcutId为<aop:pointcut>节点id的值-->
<aop:before method="onInsertBefore" pointcut-ref="pointcutId" />
<!-- (2)配置后置通知(返回通知),在目标方法后执行,onInsertAfter为 XmlAspecjJ类中自定义方法。pointcutId为<aop:pointcut>节点id的值-->
<aop:after-returning method="onInsertAfter" pointcut-ref="pointcutId" />
<!-- (3)配置环绕通知(前置+后置),在目标方法前与后都执行,onInsertBeforeAndAfter为 XmlAspecjJ类中自定义方法。pointcutId为<aop:pointcut>节点id的值-->
<aop:around method="onInsertBeforeAndAfter" pointcut-ref="pointcutId" />
<!-- (4)异常抛出通知,出现异常时执行,onInsertException为 XmlAspecjJ类中自定义方法。pointcutId为<aop:pointcut>节点id的值。throwing将异常传给自定义方法,t为方法参数名-->
<aop:after-throwing method="onInsertException" pointcut-ref="pointcutId" throwing="t" />
<!-- (5)最终通知,不管是否出现异常,总是执行,onFinally为 XmlAspecjJ类中自定义方法。pointcutId为<aop:pointcut>节点id的值-->
<aop:after method="onFinally" pointcut-ref="pointcutId" />
<!-- (6)声明使用引入通知,目标类能同时继承多个实现类 -->
<!-- <aop:declare-parents types-matching="* 目标类父接口全名" implement-interface="被继承类的父接口全名" default-impl="被继承类的全名" /> -->
</aop:aspect>
</aop:config>
</beans>
二、注解方式,配置切面类、通知方法:
1.添加aop注解支持,在applicationContext.xml中beans节点中加入:
<!-- 添加aop注解支持 -->
<aop:aspectj-autoproxy/>
2.创建切面类:
(1)在类前添加注解,使用@Aspect标为切面类:
@Aspect //@Aspect标识此类为切面类
public class XmlAspecjJ {
}
(2)配置切面类,在applicationContext.xml中beans节点中加入:
<!-- 让spring创建XmlAspecjJ自定义对象 -->
<bean id="xmlAspecjJ" class="com.yyh.hkw.dao.XmlAspecjJ" />
3.在切面类中方法前加上注解:
(1)@Before,前置通知:
// 在目标方法前执行
@Before(value = "execution(* com.yyh.hkw.dao.UserDao.insert(..))")
public void onBefore() {
System.out.println("onBefore");
}
(2)@AfterReturning返回通知(后置通知):
// 在目标方法后执行
@AfterReturning(value = "execution(* com.yyh.hkw.dao.UserDao.insert(..))")
public void onAfter() {
}
(3)@Around,环绕通知:
//在目标方法前与后都执行
@Around(value = "execution(* com.yyh.hkw.dao.UserDao.insert(..))")
public void onBeforeAndAfter(ProceedingJoinPoint joinPoint) throws Throwable {
//1.方法之前
joinPoint.getSignature().getName();// 取得在执行的方法名
joinPoint.getArgs();// 取得在执行方法的参数列表
//2执行方法
joinPoint.proceed();
//3.方法之后
}
(4)@AfterThrowing,异常通知:
//出现异常时执行, 参数名t要和throwing值一致
@AfterThrowing(value = "execution(* com.yyh.hkw.dao.UserDao.insert(..))", throwing = "t")
public void onException(Throwable t) {
System.out.println("onException: " + t.getMessage());
}
(5)@After,最终通知:
//不管是否出现异常,总是执行
@After(value = "execution(* com.yyh.hkw.dao.UserDao.insert(..))")
public void onFinally() {
}
(6)@DeclareParents,引介通知(目标类能同时继承多个实现类):
在切面类方法前加上注解,让目标接口实现类继承了别的接口实现类中的方法
@DeclareParents(value="目标接口全名", defaultImpl=被继承类的全名)
在程序中调中
被继承类的父接口 别名 = (被继承类的父接口)目标接口;
4.@Order,指定切面类的优先级:
@Aspect()
@Order(1) //放在@Aspect后面,数字小的切面类先执行
public class XmlAspecjJ {
}
5.@Pointcut,定义通用切入点方法,供其他方法调用:
(1)在公用方法前加入注解:
@Pointcut("execution(* com.yyh.hkw.dao.UserDao.insert(..))")
public void onCommon() {
}
(2)在其他方法前的注解处引用公用方法:
// 引用onCommon()方法,共用onCommon方法中定义的切入表达式
@Before("onCommon()") //在别的类中引用此公用定义:@Before("XmlAspecjJ.onCommon()")
public void onBefore() {
}