文章目录


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>

看下运行结果:

(三)Spring超全面快速入门-AspectJ开发_Spring入门

是不是超级简单?

4、@Before前置通知

@Before

可以在方法中传入JoinPoint对象,用来获得切点信息:

(三)Spring超全面快速入门-AspectJ开发_Spring_02

看下打印结果:

(三)Spring超全面快速入门-AspectJ开发_Spring_03

5、@AfterReturning后置通知

@AfterReturning

也很简单,和前置差不多,比如在查找方法后增加后置增强:

@AfterReturning(value = "execution(* demo1.UserDaoImpl.findin(..))")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("后置通知=========="+joinPoint);
}

(三)Spring超全面快速入门-AspectJ开发_Spring_04

当然后置通知还可以返回参数,比如我们把findin方法改成了返回值为String的方法,然后,只需这样配置:

(三)Spring超全面快速入门-AspectJ开发_spring_05

切记returning后的名字和afterReturning方法中的参数名字必须一样才行,看下打印结果:

(三)Spring超全面快速入门-AspectJ开发_xml_06

这里就是我返回的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;
}

看一下打印结果:

(三)Spring超全面快速入门-AspectJ开发_Spring_07

7、@AfterThrowing异常抛出通知

  • 通过throwing属性,可以设置发生异常对象参数
    必须目标方法抛出异常后才会执行:
    (三)Spring超全面快速入门-AspectJ开发_Spring_08
    经典错误:
@AfterThrowing(value = "execution(* demo1.UserDaoImpl.update())",throwing = "e")
public void AfterThrowing(Throwable e) {
System.out.println("异常抛出通知"+e.getMessage());
}

然后就可以在遇到错误时打印错误信息了:

(三)Spring超全面快速入门-AspectJ开发_xml_09

8、@After最终通知

@After(value = "execution(* demo1.UserDaoImpl.findin())")
public void Final() {
System.out.println("最终通知=======================================");
}

这样就可以完成最终通知,不管会不会报错都会在这个方法后执行:

(三)Spring超全面快速入门-AspectJ开发_xml_10

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方法执行后执行最终通知:

(三)Spring超全面快速入门-AspectJ开发_xml_11

可以看跟以前配置一样,这样就很方便的再次进行了解耦。

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表示切入点是哪个类,看看运行结果:

(三)Spring超全面快速入门-AspectJ开发_xml_12