1.使用Aspectj之前我们需要做一些准备工作,那就是所需要的jar
>spring-aop-4.0.6.RELEASE
>aspectjrt
>aspectjweaver
>aoplliance
>spring-core
2.配置文件(bean.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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.Demo6"></context:component-scan>
<!--开启自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3.ASpectj切入点表达式
1.execution() 用于描述方法[重点掌握]
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
类,[省略]
方法名,不能省略
参数
() 无参
(int) 一个整型
(int,int) 两个
(..) 参数任意
throws,可省略,一般不写。
4.Aspetj通知类型
before:前置通知(应用:各种校验), 在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理),方法正常返回后执行,如果方法中抛出异常,通知无法执行,必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情),方法执行前后分别执行,可以阻止方法的执行,必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息),方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场),方法执行完毕后执行,无论方法中是否出现异常
5.切面类
@Aspect
@Compent
上述介绍了相关知识接下来通过一个小例子来融会贯通吧
package com.Demo6;
public interface IUserDao {
public void save();
}
package com.Demo6;
import org.springframework.stereotype.Component;
@Component("userDao")
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("-----------开启连接-----------");
}
}
package com.Demo6;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAop {
@Before("execution(public void com.Demo6.UserDao.save())")
public void beginTran(){
System.out.println("...............开启事务");
}
@After("execution(public void com.Demo6.UserDao.save())")
public void commite(){
System.out.println("...............提交事务");
}
@AfterReturning("execution(public void com.Demo6.UserDao.save())")
public void afterReturn(){
System.out.println("------------使用的是AfterReturning-------------");
}
@AfterThrowing("execution(public void com.Demo6.UserDao.save())")
public void afterThrow(){
System.out.println("------------使用的是AfterThrowing-------------");
}
@Around("execution(public void com.Demo6.UserDao.save())")
public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("------------begin------------");
//开启核心事务,proceed()相当于我们的核心方法save()
proceedingJoinPoint.proceed();
System.out.println("------------end------------");
}
}
package com.Demo6;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test4 {
public static void main(String []args){
ApplicationContext ap = new ClassPathXmlApplicationContext("bean2.xml");
IUserDao proxy = (IUserDao) ap.getBean("userDao");
proxy.save();
}
}
运行后结果如下
如果我们要验证@afterThrowing我们在UserDao里面加一段代码即可
package com.Demo6;
import org.springframework.stereotype.Component;
@Component("userDao")
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("-----------开启连接-----------");
int i = 1/0;
}
}
然后在看看运行结果
我们可以知道如果有异常就不会执行@AfterReturning
但是我们从上面的MyAop中看到如果我们的每一个切入点表达式都写那么长是不是会显得有点过于繁琐,那么接下来我们介绍一个方法@PointCut,修饰方法 privatevoid xxx(){} 之后通过“方法名”获得切入点引用
修改后的代码如下
package com.Demo6;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* Created by 王宇峰 on 2018/7/26.
*/
@Component
@Aspect
public class MyAop {
@Pointcut("execution(public void com.Demo6.UserDao.save())")
public void pointcut(){}
@Before("pointcut()")
public void beginTran(){
System.out.println("...............开启事务");
}
@After("pointcut()")
public void commite(){
System.out.println("...............提交事务");
}
@AfterReturning("pointcut()")
public void afterReturn(){
System.out.println("------------使用的是AfterReturning-------------");
}
@AfterThrowing("pointcut()")
public void afterThrow(){
System.out.println("------------使用的是AfterThrowing-------------");
}
@Around("pointcut()")
public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("------------begin------------");
//开启核心事务,proceed()相当于我们的核心方法save()
proceedingJoinPoint.proceed();
System.out.println("------------end------------");
}
}
运行结果如下
当然如果我们还有一个类里面有一个方法同样要实现这个操作我们该怎么做呢
package com.Demo6;
import org.springframework.stereotype.Component;
@Component
public class OrderDao {
public void save() {
System.out.println("..............完成修改..............");
}
}
其实我们只需要在MyAop中修改一个地方就可以了
@Pointcut("execution(* *.*())")
然后在测试类Test4中加一段代码
package com.Demo6;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test4 {
public static void main(String []args){
ApplicationContext ap = new ClassPathXmlApplicationContext("bean2.xml");
IUserDao proxy = (IUserDao) ap.getBean("userDao");
proxy.save();
OrderDao orderDao = (OrderDao) ap.getBean("orderDao");
orderDao.save();
}
}
这样就可以达到我们想要的结果