需要导入的jar包,请看上一篇博客。
注解:
- 如果使用注解进行aop开发,必须进行aspectj自动代理
<aop:aspectj-autoproxy>
- 通知注解
@Before 前置
@AfterReturning 后置
@Around 环绕
@AfterThrowing 异常
@After 最终
- 切面类
@Aspect
- 声明切入点
@PointCut
(1)TeacherService.java服务接口
package com.itheima.e_aspectj_annotation;
public interface TeacherService {
public void addTeacher();
public String updateTeacher();
}
注意要把@Service注解加上。
package com.itheima.e_aspectj_annotation;
import org.springframework.stereotype.Service;
@Service
public class TeacherServiceImpl implements TeacherService {
@Override
public void addTeacher() {
System.out.println("d_aspect anno add teacher");
//int i = 1/0;
}
@Override
public String updateTeacher() {
System.out.println("d_aspect anno update teacher");
return "来来来";
}
}
(3)MyAspect.java类
注意注解,声明切面类。
package com.itheima.e_aspectj_annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,含多个通知
* @author <a>传智•左慈</a>
*
*/
@Component
@Aspect //<aop:aspect ref="myAspect">
public class MyAspect {
//@Before("execution(* com.itheima.e_aspectj_annotation.*.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知, 方法名称:" + joinPoint.getSignature().getName());
}
//@AfterReturning(value="execution(* com.itheima.e_aspectj_annotation.*.*(..))",returning="xxx")
public void myAfterReturning(JoinPoint joinPoint,Object xxx){
System.out.println("后置通知, 返回值:" + xxx);
}
//@Around("execution(* com.itheima.e_aspectj_annotation.*.*(..))")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//必须执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
//@AfterThrowing(value="execution(* com.itheima.e_aspectj_annotation.*.*(..))" ,throwing="e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
System.out.println("抛出异常通知, " + e.getMessage());
}
@After("myPonitCut()")
public void myAfter(){
System.out.println("最终");
}
/**
* 使用 @Pointcut 声明切入点表达式,必须修饰在方法:私有,没有返回值,方法名任意
* 在通知中可以通过方法获得,相当于调用方法。
*/
@Pointcut("execution(* com.itheima.e_aspectj_annotation.*.*(..))")
private void myPonitCut(){
}
}
实际上只有两个注解有用。
1、声明扫描的包
<context:component-scan base-package="com.itheima.e_aspectj_annotation"></context:component-scan>
2、
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 1 目标类
@Service
public class TeacherServiceImpl implements TeacherService {
<bean id="teacherServiceId" class="com.itheima.d_aspectj_xml.TeacherServiceImpl"></bean>
-->
<!-- 2 切面类(多个通知)
@Component
public class MyAspect {
<bean id="myAspect" class="com.itheima.d_aspectj_xml.MyAspect"></bean>
-->
<!-- 扫描 -->
<context:component-scan base-package="com.itheima.e_aspectj_annotation"></context:component-scan>
<!-- 3 aop编程
3.1特殊切面,配置一个通知 和 一个切入点
<aop:advisor advice-ref="一个通知" pointcut-ref="一个切入点"/>
3.2 就是切面,声明配置多个通知和多个切入点
<aop:aspect ref="">确定切面类,从而获得多个通知
-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--
<aop:config>
@Aspect //<aop:aspect ref="myAspect">
public class MyAspect {
<aop:aspect ref="myAspect">
3.2 配置切入点
<aop:pointcut expression="execution(* com.itheima.d_aspectj_xml.*.*(..))" id="myPonitCut"/>
3.3 声明通知类型
#1 前置通知 , 目标方法之前执行。
* 第一个参数为JoinPoint,可以获得目标方法名等。
<aop:before method="myBefore" pointcut-ref="myPonitCut"/>
#2 后置通知,目标方法之后执行,可以获得返回值。 通过“returning”属性配置第二个参数的名称,获得返回值的,类型必须Object
* 第一个参数为:JoinPoint
* 第二个参数为:Object xxx
<aop:after-returning method="myAfterReturning" pointcut-ref="myPonitCut" returning="xxx"/>
#3 环绕通知, 目标方法前后
方法要求:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
执行目标方法:joinPoint.proceed();
<aop:around method="myAround" pointcut-ref="myPonitCut"/>
#4 抛出异常通知,目标方法出现异常时才执行。通过“throwing”属性配置第二个参数的名称,获得具体的异常信息,类型必须是Throwable
* 第一个参数为:JoinPoint
* 第二个参数为:Throwable e
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPonitCut" throwing="e"/>
<aop:after method="myAfter" pointcut-ref="myPonitCut"/>
</aop:aspect>
</aop:config>
-->
</beans>
(5)TestApp.java单元测试类
package com.itheima.e_aspectj_annotation;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/itheima/e_aspectj_annotation/beans.xml")
public class TestApp {
@Autowired
private TeacherService teacherService;
@Test
public void demo01(){
//获得目标类
// String xmlPath = "com/itheima/e_aspectj_annotation/beans.xml";
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// TeacherService teacherService = (TeacherService) applicationContext.getBean("teacherServiceId");
teacherService.addTeacher();
teacherService.updateTeacher();
}
}