直接上操作步骤
步骤一:创建JavaWEB项目,引入具体的开发的jar包,这里用到的jar包参考上一篇文章
完整的jar包如下:
步骤二:创建Spring的配置文件,引入具体的AOP的schema约束
具体也可以参考上一篇文章
<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">
</beans>
步骤三:创建和配置目标类
package blog.csdn.net.mchenys.dao;
public interface UserDao {
void saveUser();
void updateUser();
}
package blog.csdn.net.mchenys.dao.impl;
import blog.csdn.net.mchenys.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存用户成功...");
}
@Override
public void updateUser() {
System.out.println("更新用户成功...");
}
}
在applicationContext.xml中注册目标类
<bean id="userDao" class="blog.csdn.net.mchenys.dao.impl.UserDaoImpl"/>
步骤四:创建和配置切面类
package blog.csdn.net.mchenys.dao;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 切面类,通过@Aspect注解声明
* @author mChenys
*
*/
@Aspect
public class MyAspectAnno {
/**
* 定义通知方法,常用的有
* @Before:前置通知
* @AfterReturing:后置通知
* @Around:环绕通知
* @After:最终通知
* @AfterThrowing:异常抛出通知
*
* value的值是切入点表达式
*/
@Before(value="execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void log() {
System.out.println("记录日志");
}
}
在applicationContext.xml中注册切面类
<bean id="myAspectAnno" class="blog.csdn.net.mchenys.dao.MyAspectAnno"/>
步骤五:在配置文件中开启自动代理
<aop:aspectj-autoproxy/>
完整的applicationContext.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 definitions here -->
<!-- 开启自动代理 -->
<aop:aspectj-autoproxy/>
<!-- 注册目标类 -->
<bean id="userDao" class="blog.csdn.net.mchenys.dao.impl.UserDaoImpl"/>
<!-- 注册切面类 -->
<bean id="myAspectAnno" class="blog.csdn.net.mchenys.dao.MyAspectAnno"/>
</beans>
最后编写测试类
package blog.csdn.net.mchenys.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import blog.csdn.net.mchenys.dao.UserDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
@Resource(name="userDao") //注入xml中配置的目标类
private UserDao userDao;
@Test
public void test1() {
userDao.saveUser();
}
}
运行后看到如下结果说明配置成功了
配置通用的切入点
当你的切面类有多个通知方法都对应同一个切入点(目标类的某个方法)时,你会发现你需要重复写很多个相同的切入点表达式,例如:
@Before(value = "execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void log() {
System.out.println("记录日志");
}
@After(value = "execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void after() {
System.out.println("最终通知");
}
@Around(value = "execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知1");
try {
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知2");
}
有没有简便的方式呢?答案是有的
具体方式就是在切面了中定义一个通用的切入点方法,如下所示,方法名任意起
/**
* 定义通用的切入点
*/
@Pointcut(value="execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void fn(){}
然后将所有的通知方法的切入点表达式替换成 切面类名.通用切入点方法()
,例如MyAspectAnno.fn()
完整的切面类如下:
package blog.csdn.net.mchenys.dao;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 切面类,通过@Aspect注解声明
*
* @author mChenys
*
*/
@Aspect
public class MyAspectAnno {
/**
* 定义通用的切入点
*/
@Pointcut(value = "execution(public void blog.csdn.net.mchenys.dao.impl.UserDaoImpl.saveUser())")
public void fn() {}
/**
* value不再是书写切入点表达式了,而是引入定义好的通用的切入点
*/
@Before(value = "MyAspectAnno.fn()")
public void log() {
System.out.println("记录日志");
}
@After(value = "MyAspectAnno.fn()")
public void after() {
System.out.println("最终通知");
}
@Around(value = "MyAspectAnno.fn()")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知1");
try {
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知2");
}
}
最后,测试类在执行一次,结果如下说明ok
通过执行结果也可以发现,环绕通知是优先于前置通知执行的.