一. Spring AOP 面向切面编程(也叫面向方面编程)

  1. AOP本质上就是一种代理模式
    Aspect Oriented Programming(AOP)是 Spring框架中的核心内容之一。本质上是一种代理模式——Spring AOP就是基于动态代理的。

Spring的初体验-3_aop


有了动态代理,Spring就可以对其管理的对象的业务逻辑处理流程进行干预——Spring可以在处理流程中插一脚,干点什么事。

Spring的初体验-3_aop_02


可以干点什么呢?

分离业务代码,提高程序的可重用性。

  1. AOP的应用场景和要解决的问题

Spring的初体验-3_目标对象_03


AOP的应用场景是相互独立的各个类的方法中总存在着一些相同的业务代码。这些相同的业务代码由于是分布在不相干的各个类中(类之间甚至没有公共的接口),要想通过继承关系(垂直方向的代码复用)进行代码复用比较困难。把重复的代码封装成公共的方法再调用又会造成对各个类的代码侵入(增加了耦合度)。所以就希望能有一种方式可以把分布在不同类方法中的相同代码段抽离出来复用,又不会对原来的各个类造成代码的侵入。AOP应运而生。

  1. 使用AOP复用代码

Spring的初体验-3_目标对象_04

AOP的方法就是利用动态代理,代理各目标对象,然后将各个被代理类方法中相同的代码片段统一拿到代理类中。这样就好像在各个并列的被代理对象中横向切一刀,把公共的代码切片拿出来放到代理类中统一处理——这是一种横向的代码复用方式。

  1. 具体概念可以参考​​这里​
  2. 代码实例

二. Spring AOP的示例

  1. Spring中使用AOP涉及的jar包
aopalliance.jar
aspectjweaver-1.6.6.jar
spring-aspects-4.0.6.RELEASE.jar
  1. Spring的配置文件配置AOP
<?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 id="studentServiceAspect" class="com.bee.advice.StudentServiceAspect"></bean>

<bean id="studentService" class="com.bee.service.impl.StudentServiceImpl"></bean>

<aop:config>
<aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
AOP只能作用于方法,下边的定义是用于匹配方法的(包括返回值,函数名,参数)。
匹配的方法就是StudentService接口中定义的抽象方法。
<aop:pointcut expression="execution(* com.bee.service.*.*(..))" id="businessService"/>
<aop:before method="doBefore" pointcut-ref="businessService"/>
<aop:after method="doAfter" pointcut-ref="businessService"/>
<aop:around method="doAround" pointcut-ref="businessService"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>
<aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>

expression属性值表达式的含义:

execution(  *     com.bee.service.   *    .     *        ( .. )    )

其中​​*​​​表示匹配任意名称,​​..​​表示匹配任意个数的参数。

  1. 定义被代理的对象(目标对象Target)
package com.bee.service;

public interface StudentService {
void addStudent(String name);
}
------------------------------------------------------------------------
package com.bee.service.impl;

public class StudentServiceImpl implements StudentService{
@Override
public void addStudent(String name) {
// System.out.println("开始添加学生"+name); 不使用AOP产生的代码侵入
System.out.println("添加学生"+name); //目标对象的业务逻辑
System.out.println(1/0); //目标对象产生异常
// System.out.println("完成学生"+name+"的添加"); 不使用AOP产生的代码侵入
}
}
  1. 定义切面(Aspect)
    这里定义的是横向抽取出来的公共代码。
package com.bee.advice;

public class StudentServiceAspect {

public void doBefore(JoinPoint jp){
System.out.println("类名:"+jp.getTarget().getClass().getName());
System.out.println("方法名:"+jp.getSignature().getName());
System.out.println("开始添加学生:"+jp.getArgs()[0]);
}

public void doAfter(JoinPoint jp){
System.out.println("类名:"+jp.getTarget().getClass().getName());
System.out.println("方法名:"+jp.getSignature().getName());
System.out.println("学生添加完成:"+jp.getArgs()[0]);
}

public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("添加学生前");
Object retVal=pjp.proceed(); //执行目标对象匹配的方法
System.out.println(retVal);
System.out.println("添加学生后");
return retVal; //返回目标对象匹配方法的返回值
}

public void doAfterReturning(JoinPoint jp){
System.out.println("返回通知");
}

public void doAfterThrowing(JoinPoint jp,Throwable ex){
System.out.println("异常通知");
System.out.println("异常信息:"+ex.getMessage());
}
}
  1. 测试
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
StudentService studentService=(StudentService)ac.getBean("studentService");
studentService.addStudent("张麻子");