版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34598667/article/details/83536346
上一章我们已经学过使用XML的方式实现AOP:
https://blog.csdn.net/qq_34598667/article/details/83502426
本章我们学习一下使用注解的方式实现AOP
Spring使用注解的方式实现AOP的开发
本章所需知识点
1、开启aop注解的自动代理
< aop:aspectj-autoproxy/>
2、 AspectJ的AOP的注解:
- @Aspect:定义切面类的注解
- 通知类型:
@Before:前置通知
@AfterReturing:后置通知
@Around:环绕通知
@After:最终通知
@AfterThrowing:异常抛出通知. - @Pointcut:定义切入点的注解
3、切入点语法表达式(与xml方式一样)
语法:execution(表达式)
表达式语法:[方法访问修饰符] 方法返回值包名.类名.方法名(方法的参数)
例1:
execution (* com.oak.service.impl.UserServiceImpl.*(…)) :匹配UserServiceImpl类中声明的所有方法。
第一个 * :代表任意修饰符及任意返回值类型
第二个 * :代表任意方法,
… :匹配任意数量任意类型的参数,若目标类与该切面在同一个包中,可以省略包名。
例2:execution public double cn.itcast.service.impl.PersonServiceImpl.*(…):匹配PersonServiceImpl类中返回值类型为double类型的所有公有方法。
实现案例
本章案例基于上一章使用xml的方式实现AOP的项目上继续完成:
1)编写目标类
创建接口InfoService
public interface InfoService {
void save();
void update();
void delete();
void find();
}
创建实现类InfoServiceImpl
public class InfoServiceImpl implements InfoService{
@Override
public void save() {
System.out.println("I am the method for save ");
}
@Override
public void update() {
System.out.println("I am the method for update ");
}
@Override
public void delete() {
System.out.println("I am the method for delete ");
}
@Override
public void find() {
System.out.println("I am the method for find ");
}
}
2)配置目标类
<!--配置目标类 -->
<bean id="infoService" class="com.oak.service.InfoServiceImpl"></bean>
3)开启aop自动代理
<!--配置目标类 -->
<bean id="infoService" class="com.oak.service.InfoServiceImpl"></bean>
<!-- 开启aop的自动代理 -->
<aop:aspectj-autoproxy/>
4)编写切面类MyAspectAnno
声明切入点和通知方法
@Aspect
public class MyAspectAnno {
//声明一个切入点,anyMethod为切入点名称,指定切入点,哪些方法需要通知
@Pointcut("execution (* com.oak.service.InfoService.*(..))")
private void anyMethod(){}
//声明该方法是一个前置通知:在目标方法开始之前执行
@Before("anyMethod()")
public void doBeforeCheck() {
System.out.println("前置通知");
}
}
5)配置切面类
<!--配置切面类-->
<bean id="myAspectAnno" class="com.oak.aop.MyAspectAnno"></bean>
6)测试
在测试类中编写测试方法
@Test
public void aopAnnoTest(){
ApplicationContext cxt =
new ClassPathXmlApplicationContext
("applicationContext.xml");
InfoService infoService=cxt.getBean("infoService",InfoService.class);
infoService.save();
}
测试结果是:
前置通知
I am the method for save
7)其他通知
修改切面类,使用注解加上其他通知
@Aspect
public class MyAspectAnno {
//声明一个切入点,anyMethod为切入点名称,指定切入点,哪些方法需要通知
@Pointcut("execution (* com.oak.service.InfoService.*(..))")
private void anyMethod(){}
//声明该方法是一个前置通知:在目标方法开始之前执行
@Before("anyMethod()")
public void doBeforeCheck() {
System.out.println("前置通知");
}
@AfterReturning("anyMethod()")
public void doAfterReturning() {
System.out.println("后置通知");
}
@After("anyMethod()")
public void doAfter() {
System.out.println("最终通知");
}
@AfterThrowing("anyMethod()")
public void doAfterThrowing() {
System.out.println("异常通知");
}
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
/**
* 环绕通知内部一定要确保执行该方法,如果不执行该方法,业务bean中被拦截的方法就不会被执行。
* 当执行该方法,如果后面还有切面的话,它的执行顺序应该是这样的:先执行后面的切面,如果后面没有切面了,
* 再执行最终的目标对象的业务方法。若不执行该方法,则后面的切面,业务bean的方法都不会被执行。
*/
// if () { // 判断用户是否有权限,
System.out.println("进入方法");
Object result = pjp.proceed();
System.out.println("退出方法");
// }
return result;
}
}
注意:环绕通知内部一定要确保执行proceed()该方法,如果不执行该方法,业务bean中被拦截的方法就不会被执行。当执行该方法,如果后面还有切面的话,它的执行顺序应该是这样的:先执行后面的切面,如果后面没有切面了,再执行最终的目标对象的业务方法。若不执行该方法,则后面的切面,业务bean的方法都不会被执行。
运行测试:
进入方法
前置通知
I am the method for save
退出方法
最终通知
后置通知