文章目录
1、@AspectJ提供不同的通知类型
-
@Before 前置通知,相当于MethodBeforeAdvice
-
@AfterReturning 后置通知,相当于AfterReturningAdvice
-
@Around 环绕通知,相当于MethodInterceptor
-
@AfterThrowing异常抛出通知,相当于ThrowAdvice
-
@After 最终final通知,不管是否异常,该通知都会执行(相当于finally代码块)
-
@DeclareParents 引介通知,相当于IntroductionInterceptor(不必掌握)
2、需要依赖的Jar包
Spring四大基本包: spring-core, spring-context, spring-expression, spring-beans
测试包: junit切记一定要4.1版本或以上,不要使用3.X版本的,否则@Runwith注解用不了
spring测试包: spring-test
AOP联盟aopaliance和spring-aop两个包
AspectJ两个包 :aspectjweaver和spring-aspects
3、入门案例
还是老三样:目标类、通知类、配置信息
目标类:
package demo1;
public class UserDaoImpl implements UserDao {
@Override
public void insert() {
System.out.println("新增用户...");
}
@Override
public void update() {
System.out.println("更新用户...");
}
@Override
public void delete() {
System.out.println("删除用户...");
}
@Override
public void findin() {
System.out.println("查找用户...");
}
}
通知类:
package demo1;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspectJAnno {
@Before(value="execution(* demo1.UserDaoImpl.*(..))")
public void before() {
System.out.println("==========前置通知========");
}
}
需要注意的是应该在类前面加@Aspect注解,这样才能使其变成切面类,在要执行通知的前面加@Before注解,后面的value里面是"execution(要增强的目标类信息的包,正则表达式)"
看下配置文件:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启AspectJ的注解,自动代理-->
<aop:aspectj-autoproxy/>
<!--设置目标类-->
<bean id="userDao" class="demo1.UserDaoImpl"/>
<!--定义切面-->
<bean class="demo1.MyAspectJAnno"/>
</beans>
看下运行结果:
是不是超级简单?
4、@Before前置通知
@Before
可以在方法中传入JoinPoint对象,用来获得切点信息:
看下打印结果:
5、@AfterReturning后置通知
@AfterReturning
也很简单,和前置差不多,比如在查找方法后增加后置增强:
@AfterReturning(value = "execution(* demo1.UserDaoImpl.findin(..))")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("后置通知=========="+joinPoint);
}
当然后置通知还可以返回参数,比如我们把findin方法改成了返回值为String的方法,然后,只需这样配置:
切记returning后的名字和afterReturning方法中的参数名字必须一样才行,看下打印结果:
这里就是我返回的String
6、@Round环绕通知
- around方法的返回值是目标代理方法的返回值
- 参数为ProceedingJoinPoint可以调用拦截目标方法执行
环绕通知可以在某个方法前后进行增强,当然也可以不执行这个方法,看个例子:
@Around(value = "execution(* demo1.UserDaoImpl.delete(..))")
public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前增强===========");
Object obj = joinPoint.proceed();
System.out.println("环绕后增强===========");
return obj;
}
看一下打印结果:
7、@AfterThrowing异常抛出通知
- 通过throwing属性,可以设置发生异常对象参数
必须目标方法抛出异常后才会执行:
经典错误:
@AfterThrowing(value = "execution(* demo1.UserDaoImpl.update())",throwing = "e")
public void AfterThrowing(Throwable e) {
System.out.println("异常抛出通知"+e.getMessage());
}
然后就可以在遇到错误时打印错误信息了:
8、@After最终通知
@After(value = "execution(* demo1.UserDaoImpl.findin())")
public void Final() {
System.out.println("最终通知=======================================");
}
这样就可以完成最终通知,不管会不会报错都会在这个方法后执行:
9、@Pointcut为切点命名
- 在每个通知内定义切点,会造成工作量巨大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
- 切点方法: private void无参数方法,方法名为切点名
- 当通知有多个切点时,可是使用“||”进行连接
使用方法:
@Pointcut(value = "execution(* demo1.UserDaoImpl.findin())")
private void demo1() {}
只定义一个空方法,然后这个切点就是只增强findin();方法的,然后我们在需要增强findin的通知方法名写成demo1()就可以了:
@After(value = "demo1()")
public void Final() {
System.out.println("最终通知=======================================");
}
这样就是在findin方法执行后执行最终通知:
可以看跟以前配置一样,这样就很方便的再次进行了解耦。
10、基于XML的方式开发AOP
目标类还是UserDao,我们看看切面类怎么写:
package demo2;
public class MySpringAdvicor {
public void before() {
System.out.println("-*-*-*-*-*-*XML前置增强通知*-*-*-*-*-*-*-");
}
}
巨简单,什么都不用配置,因为要去配置文件配置,看看XML:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--设置目标类-->
<bean id="userDao" class="demo2.UserDaoImpl"/>
<!--设置切面类-->
<bean id="myAdvisor" class="demo2.MySpringAdvicor"/>
<!--配置切面类-->
<aop:config>
<!--设置切入点-->
<aop:pointcut id="pointcut1" expression="execution(* demo2.UserDao.delete(..))"/>
<!--设置增强方式-->
<aop:aspect ref="myAdvisor">
<aop:before method="before" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
需要设置切面类,标签是aop:config,内部一个是aop:aspect表示的是切面是哪个,aop:pointcut表示切入点是哪个类,看看运行结果: