1. 开发的步骤
(1)导入AOP相关坐标
在pom.xml中

(2)创建目标接口和目标类(内部有切点)
(3)创建切面类(内部有增强方法)
(4)将目标类和切面类的对象创建权交给spring
(5)在applicationContext.xml中配置织入关系
(6)测试代码
案例:

(1)导入AOP相关坐标,pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.company</groupId> <artifactId>spring_aop</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
(2)创建目标接口(TargetInterface)和目标类(Target),切点是save()方法
TargetInterface.java
package com.company.aop;
public interface TargetInterface {
void save();
}
Target.java
package com.company.aop;
public class Target implements TargetInterface {
public void save() {
System.out.println("save running ...");
}
}
(3)创建切面类,增强方法是before()方法
package com.company.aop;
public class MyAspect {
public void before() {
System.out.println("前置增强........");
}
}
(4)将目标对象和切面对象的创建权交给spring,在applicationContext.xml中配置,Spring的很多功能首要条件就是这些bean要放到容器中,spring才能在容器中拿出对象,进行相应的操作。

(5)在applicationContext.xml中配置织入关系,method="before"是myAspect的before()方法

完整版的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 id="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--切面:切点+通知--> <aop:before method="before" pointcut="execution(public void com.company.aop.Target.save())"></aop:before> </aop:aspect> </aop:config> </beans>
(6)测试 ,AopTest.java
package com.company.test;
import com.company.aop.TargetInterface;
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:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface targetInterface;
@Test
public void test1() {
targetInterface.save();
}
}
运行结果:

2. 切点表达式的写法

<aop:before method="before" pointcut="execution(public void com.company.aop.Target.save())"></aop:before>
(1)访问修饰符可以省略
(2)返回值类型、包名、类名、方法名可以使用星号*代表任意
(3)包名与类名之间一个点.代表当前包下的类,两个点..表示当前包及其子包下的类
(4)参数列表可以使用两个点..表示任意个数,任意类型的参数列表
例如:
excution(public void com.company.aop.Target.method())
excution(void com.company.aop.Target.*(..)) *表示任意方法,(..)表示参数任意个
excution(* com.company.aop.*.*(..)) aop包下的任意类,任意方法,这种形式最常用
excution(* com.company.aop..*.*(..)) aop包及其子包下的任意类,任意方法
excution(* *..*.*(..))
上面的可以改成这样
<aop:before method="before" pointcut="execution(* com.company.aop.*.*(..))"></aop:before>
3. 通知的类型



3.1. 后置通知
在原来的切面类中加如后置增强方法
MyAspect.java
package com.company.aop;
public class MyAspect {
public void before() {
System.out.println("前置增强........");
}
public void afterReturning() {
System.out.println("后置增强");
}
}
再在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 id="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--切面:切点+通知--> <aop:before method="before" pointcut="execution(* com.company.aop.*.*(..))"></aop:before> <aop:after-returning method="afterReturning" pointcut="execution(* com.company.aop.*.*(..))"></aop:after-returning> </aop:aspect> </aop:config> </beans>
执行AopTest.java
运行结果:

3.2. 环绕通知
在原来的切面类中加入环绕通知方法
MyAspect.java
package com.company.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("前置增强........");
}
public void afterReturning() {
System.out.println("后置增强");
}
// ProceedingJoinPoint 正在执行的连接点 === 切点
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前增强.....");
// 切点方法
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕后增强.....");
return proceed;
}
}
再在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 id="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--切面:切点+通知--> <!-- <aop:before method="before" pointcut="execution(* com.company.aop.*.*(..))"></aop:before>--> <!-- <aop:after-returning method="afterReturning" pointcut="execution(* com.company.aop.*.*(..))"></aop:after-returning>--> <aop:around method="around" pointcut="execution(* com.company.aop.*.*(..))"></aop:around> </aop:aspect> </aop:config> </beans>
执行AopTest.java
运行结果:

3.3 异常抛出通知
在MyAspect.java中加入异常抛出增强方法
package com.company.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("前置增强........");
}
public void afterReturning() {
System.out.println("后置增强");
}
// ProceedingJoinPoint 正在执行的连接点 === 切点
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前增强.....");
// 切点方法
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕后增强.....");
return proceed;
}
public void afterThrowing() {
System.out.println("异常抛出增强.....");
}
}
异常抛出的是目标对象中的异常,因此在Target中构造异常
Target.java
package com.company.aop;
public class Target implements TargetInterface {
public void save() {
int i = 1/0;
System.out.println("save running ...");
}
}
再在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 id="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--切面:切点+通知--> <!-- <aop:before method="before" pointcut="execution(* com.company.aop.*.*(..))"></aop:before>--> <!-- <aop:after-returning method="afterReturning" pointcut="execution(* com.company.aop.*.*(..))"></aop:after-returning>--> <aop:around method="around" pointcut="execution(* com.company.aop.*.*(..))"/> <aop:after-throwing method="afterThrowing" pointcut="execution(* com.company.aop.*.*(..))"/> </aop:aspect> </aop:config> </beans>
执行AopTest.java
运行结果:

3.4 最终通知
在MyAspect.java中加入最终增强方法
package com.company.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("前置增强........");
}
public void afterReturning() {
System.out.println("后置增强");
}
// ProceedingJoinPoint 正在执行的连接点 === 切点
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前增强.....");
// 切点方法
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕后增强.....");
return proceed;
}
public void afterThrowing() {
System.out.println("异常抛出增强.....");
}
public void after() {
System.out.println("最终增强.....");
}
}
再在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 id="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--切面:切点+通知--> <!-- <aop:before method="before" pointcut="execution(* com.company.aop.*.*(..))"/>--> <!-- <aop:after-returning method="afterReturning" pointcut="execution(* com.company.aop.*.*(..))"/>--> <aop:around method="around" pointcut="execution(* com.company.aop.*.*(..))"/> <aop:after-throwing method="afterThrowing" pointcut="execution(* com.company.aop.*.*(..))"/> <aop:after method="after" pointcut="execution(* com.company.aop.*.*(..))"/> </aop:aspect> </aop:config> </beans>
运行结果:

4.切点表达式抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式

<?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="target" class="com.company.aop.Target"></bean> <!--切面对象--> <bean id="myAspect" class="com.company.aop.MyAspect"></bean> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置,后置)--> <aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!--抽取切点表达式--> <aop:pointcut id="myPointcut" expression="execution(* com.company.aop.*.*(..))"/> <aop:around method="around" pointcut-ref="myPointcut"/> <aop:after method="after" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>