1、概念
(1)AspectJ是一个基于Java语言的AOP框架
(2)Spring2.0以后新增了对AspectJ切入点表达式的支持
(3)AspectJ是AspectJ1.5的新增功能,通过JDK5注解技术,允许在Bean类中定义切面。新版本的Spring框架建议使用AspectJ方式来开发AOP
2、切入点表达式
(1)execution():用语描述方法
语法:execution(修饰符、返回值、包、类、方法(参数)、异常)
修饰符:一般省略
public:公共方法
*:任意
返回值
void:没有返回值
String:返回值为字符串
*:返回值任意
方法:不能省略
参数
(..)参数任意
(2)案例:
<aop:pointcut id="myPointCut" expression="execution(* pers.zhb.proxy.*.*(..))"></aop:pointcut>
(3)其他表达式
within:匹配包或者子包中的方法
this:匹配接口中代理对象中的方法
target:匹配实现接口的目标对象的方法
args:匹配参数格式符合标准的方法
bean:对指定bean所有的方法
2、AspectJ通知类型
(1)aop联盟定义通知类型:具有特性接口,必须实现,从而确定方法名称。
(2)aspectj通知类型:只定义类型名称。已经方法格式。
before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
afterRetuming:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值
around:环统通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行。
必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
after最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
3、导入jar包(四个)
aop联盟规范
spring aop实现
aspect规范
spring aspect实现
4、源码
(1)AspectJAfterThrowingAdvice
(2)AspectJAfterAdvice
5、基于XML文件的配置(前置通知)
(1)目标类的接口和实现类:
public interface StudentService {
void addStudent();
void updateStudent();
void deleteStudent();
}
public class StudentServiceImpl implements StudentService {
@Override
public void addStudent() {
System.out.println("addStudent");
}
@Override
public void updateStudent() {
System.out.println("updateStudent");
}
@Override
public void deleteStudent() {
System.out.println("deleteStudent");
}
}
(2)切面类(含有通知):
public class MyAspect {
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
}
(3)配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
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="studentService" class="pers.zhb.aspectxml.StudentServiceImpl"></bean>
<!--切面类-->
<bean id="myAspect" class="pers.zhb.aspectxml.MyAspect"></bean>
<!--aop编程
将切面类声明为切面,从而获得通知(方法)
ref:切面类引用
-->
<aop:config>
<aop:aspect ref="myAspect">
<!--引入切面类,从中获得通知(方法)
expression:切入点表达式
id:名称,用于其他通知引用
-->
<aop:pointcut id="myPointCut" expression="execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))"></aop:pointcut>
<!--
method:通知,即方法名
pointcut:切入点表达式,此表达式只能当前通知使用
pointcut-ref:切入点的引用,可以和其它通知共享切入点
-->
<aop:before method="before" pointcut-ref="myPointCut"></aop:before>
</aop:aspect>
</aop:config>
</beans>
(4)测试类:
public class TestAspectXml {
public static void main(String[] args) {
ApplicationContext applicationContext=new
ClassPathXmlApplicationContext("applicationContext.xml");
//获得目标类
pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
studentService.addStudent();
studentService.deleteStudent();
studentService.updateStudent();
}
}
前置通知:addStudent
addStudent
前置通知:deleteStudent
deleteStudent
前置通知:updateStudent
updateStudent
6、基于XML文件的配置(后置通知)
(1)定义接口和接口的实现类:
public interface StudentService {
void addStudent();
void updateStudent();
String deleteStudent();
}
public class StudentServiceImpl implements StudentService {
@Override
public void addStudent() {
System.out.println("addStudent");
}
@Override
public void updateStudent() {
System.out.println("updateStudent");
}
@Override
public String deleteStudent() {
System.out.println("deleteStudent");
return "nihao";
}
}
(2)切面类:
public class MyAspect {
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
//参数二:类型Object,参数名returning配置的
System.out.println("后置通知:"+ joinPoint.getSignature().getName()+" "+ret);
}
}
(3)配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
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="studentService" class="pers.zhb.aspectxml.StudentServiceImpl"></bean>
<!--切面类-->
<bean id="myAspect" class="pers.zhb.aspectxml.MyAspect"></bean>
<!--aop编程
将切面类声明为切面,从而获得通知(方法)
ref:切面类引用
-->
<aop:config>
<aop:aspect ref="myAspect">
<!--引入切面类,从中获得通知(方法)
expression:切入点表达式
id:名称,用于其他通知引用
-->
<aop:pointcut id="myPointCut" expression="execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))"></aop:pointcut>
<!--
method:通知,即方法名
pointcut:切入点表达式,此表达式只能当前通知使用
pointcut-ref:切入点的引用,可以和其它通知共享切入点
returning:通知方法第二个参数的名称
-->
<aop:before method="before" pointcut-ref="myPointCut"></aop:before>
<aop:after-returning method="after" pointcut-ref="myPointCut" returning="ret"></aop:after-returning>
</aop:aspect>
</aop:config>
</beans>
(4)测试类:
public class TestAspectXml {
public static void main(String[] args) {
ApplicationContext applicationContext=new
ClassPathXmlApplicationContext("applicationContext.xml");
//获得目标类
pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
studentService.addStudent();
studentService.deleteStudent();
studentService.updateStudent();
}
}
前置通知:addStudent
addStudent
后置通知:addStudent null
前置通知:deleteStudent
deleteStudent
后置通知:deleteStudent nihao
前置通知:updateStudent
updateStudent
后置通知:updateStudent null
7、基于XML文件的配置(环绕通知)
(1)切面类:
public class MyAspect {
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
//参数二:类型Object,参数名returning配置的
System.out.println("后置通知:"+ joinPoint.getSignature().getName()+" "+ret);
}
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
//手动执行目标方法
System.out.println("前");
Object object=proceedingJoinPoint.proceed();
System.out.println("后");
return null;
}
}
(2)配置文件:
<aop:around method="around" pointcut-ref="myPointCut"></aop:around>
(3)测试结果:
前置通知:addStudent
前
addStudent
后
后置通知:addStudent null
前置通知:deleteStudent
前
deleteStudent
后
后置通知:deleteStudent null
前置通知:updateStudent
前
updateStudent
后
后置通知:updateStudent null
8、基于XML文件的配置(抛出异常)
(1)定义目标类的接口和接口的实现类:
public interface StudentService {
void addStudent();
void updateStudent();
String deleteStudent();
}
在方法中制造异常:
public class StudentServiceImpl implements StudentService {
@Override
public void addStudent() {
System.out.println("addStudent");
}
@Override
public void updateStudent() {
int num=9/0;
System.out.println("updateStudent");
}
@Override
public String deleteStudent() {
System.out.println("deleteStudent");
return "nihao";
}
}
(2)切面类:
public class MyAspect {
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
//参数二:类型Object,参数名returning配置的
System.out.println("后置通知:"+ joinPoint.getSignature().getName()+" "+ret);
}
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
//手动执行目标方法
System.out.println("前");
Object object=proceedingJoinPoint.proceed();
System.out.println("后");
return null;
}
public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println("抛出异常的通知:"+throwable.getMessage());
}
}
(3)配置文件:
<aop:after-throwing method="AfterThrowing" pointcut-ref="myPointCut" throwing="throwable"></aop:after-throwing>
(4)测试:
前置通知:addStudent
前
addStudent
后
后置通知:addStudent null
前置通知:deleteStudent
前
deleteStudent
后
后置通知:deleteStudent null
前置通知:updateStudent
前
抛出异常的通知:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
9、基于XML文件的配置(最终通知)
(1)目标类的接口和接口的实现类:
public interface StudentService {
void addStudent();
void updateStudent();
String deleteStudent();
}
public class StudentServiceImpl implements StudentService {
@Override
public void addStudent() {
System.out.println("addStudent");
}
@Override
public void updateStudent() {
int num=9/0;
System.out.println("updateStudent");
}
@Override
public String deleteStudent() {
System.out.println("deleteStudent");
return "nihao";
}
}
(2)切面类:
public class MyAspect {
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
//参数二:类型Object,参数名returning配置的
System.out.println("后置通知:"+ joinPoint.getSignature().getName()+" "+ret);
}
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
//手动执行目标方法
System.out.println("前");
Object object=proceedingJoinPoint.proceed();
System.out.println("后");
return null;
}
public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println("抛出异常的通知:"+throwable.getMessage());
}
public void myafter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
(3)配置文件:
<aop:after method="myafter" pointcut-ref="myPointCut"></aop:after>
(4)测试结果:
前置通知:addStudent
前
addStudent
最终通知
后
后置通知:addStudent null
前置通知:deleteStudent
前
deleteStudent
最终通知
后
后置通知:deleteStudent null
前置通知:updateStudent
前
最终通知
抛出异常的通知:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
不管有没有异常都会执行最终通知。
10、基于注解的配置
(1)目标类的接口和接口的实现类:
public interface StudentService {
void addStudent();
void updateStudent();
String deleteStudent();
}
import org.springframework.stereotype.Service;
@Service("studentService")
public class StudentServiceImpl implements StudentService {
@Override
public void addStudent() {
System.out.println("addStudent");
}
@Override
public void updateStudent() {
int num=9/0;
System.out.println("updateStudent");
}
@Override
public String deleteStudent() {
System.out.println("deleteStudent");
return "nihao";
}
}
(2)配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
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">
<!--扫描注解-->
<context:component-scan base-package="pers.zhb.aspectxml"></context:component-scan>
<!--确定aop注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
(3)切面:
@Component
@Aspect//声明切面
public class MyAspect {
@Before("execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))")
public void before(JoinPoint joinPoint){
System.out.println("前置通知:"+ joinPoint.getSignature().getName());
}
//声明公共切入点
@Pointcut("execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))")
private void myPointCut(){
}
@AfterReturning(value = "myPointCut()",returning = "ret")
public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
//参数二:类型Object,参数名returning配置的
System.out.println("后置通知:"+ joinPoint.getSignature().getName()+" "+ret);
}
@Around(value = "myPointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
//手动执行目标方法
System.out.println("前");
Object object=proceedingJoinPoint.proceed();
System.out.println("后");
return null;
}
@AfterThrowing(value = "execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))",throwing = "throwable")
public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
System.out.println("抛出异常的通知:"+throwable.getMessage());
}
@After(value = "myPointCut()")
public void myafter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
(4)测试:
public class TestAspectXml {
public static void main(String[] args) {
ApplicationContext applicationContext=new
ClassPathXmlApplicationContext("applicationContext.xml");
//获得目标类
pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
studentService.addStudent();
studentService.deleteStudent();
studentService.updateStudent();
}
}
前
前置通知:addStudent
addStudent
后
最终通知
后置通知:addStudent null
前
前置通知:deleteStudent
deleteStudent
后
最终通知
后置通知:deleteStudent null
前
前置通知:updateStudent
最终通知
抛出异常的通知:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero