9.1 概览
9.1.1 简介
AOP是面向切面编程,是Spring将代理模式进行整合优化所形成的一种程序设计方法或者思想,是面向对象的一种延续。
9.1.2 Maven依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
9.1.3 关键词
横切关注点: 跨越应用程序多个模块的方法或功能。换而言之,与业务逻辑无关,但需要我们关注的部分,就是横切关注点,如:日志、安全、缓存、事务。。。。。。。。
切面(ASPECT): 横切关注点被模块化的特殊对象。即,它是一个类
通知(Advice): 切面必须要完成的工作,即类中的一个方法
目标(Target): 被通知的对象
代理(Proxy): 向目标对象应用通知之后,创建的对象
切入点(PointCut): 切面通知执行的“地点”的定义
连接点(JoinPoint): 与切入点匹配的执行点
9.1.4 五种Advice
通知类型 | 连接点 | 实现接口 |
---|---|---|
前置通知 | 方法前 | org.springframework.aop.MethodBeforeAdvice |
后置通知 | 方法后 | org.springframework.aop.AfterReturningAdvice |
环绕通知 | 方法前后 | org.aopalliance.intercept.MethodInterceptor |
异常抛出通知 | 方法抛出异常 | org.springframework.aop.ThrowsAdvice |
引介通知 | 类中增加新的方法属性 | ort.springframework.aop.IntroductionIntercepto |
9.2 数据环境
UserService:
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
UserServiceImp:
public class UserServiceImp implements UserService{
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void select() {
System.out.println("查询 一个用户");
}
}
测试接口:
import com.yun.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService =(UserService) context.getBean("userService");
userService.add();
}
}
9.3 方式一,Spring的API接口
Log.java:
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//Method:要执行的目标对象的方法
//args:参数
//target:目标对象
@Override
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
AfterLog.java:
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了,并且返回值是"+returnValue);
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userService" class="com.yun.service.UserServiceImp"/>
<bean id="log" class="com.yun.log.Log"/>
<bean id="afterLog" class="com.yun.log.AfterLog"/>
<!-- 配置aop-->
<aop:config>
<!-- 需要切入点,指定在哪儿执行,expression则是位置指定-->
<aop:pointcut id="pointcut" expression="execution(* com.yun.service.UserServiceImp.*(..))"/>
<!-- 配置通知-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
9.4 方式二,自定义AOP
MyLog.java:
package com.yun.mylog;
public class MyLog {
public void before(){
System.out.println("========before===========");
}
public void after(){
System.out.println("========after========");
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.yun.service.UserServiceImp"/>
<bean id="myLog" class="com.yun.mylog.MyLog"/>
<aop:config>
<!-- 定义切面-->
<aop:aspect ref="myLog">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.yun.service.UserServiceImp.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
提示: 使用起来,比方式一要简单一点,但是相应的,功能便没有方式一那么丰富。
关于execution(* com.yun.service.UserServiceImp.*(..))表达式:
execution内部可以分为两部分,第一部分是返回值类型,第二部分是方法,或者包的位置。
-
第一部分:表示返回类型,一个 * 表示所有的类型。
-
第二部分:表示需要横向功能扩展的位置,也就是所谓的切入点。这一部分的 * 号,表示是该类下的任意方法,(…) 表示的是参数情况,意为任意参数。
9.5 方式三,注解实现
AnnotationPointCut.java:
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.yun.service.UserServiceImp.*(..))")
public void before(){
System.out.println("这是在方法执行前");
}
@After("execution(* com.yun.service.UserServiceImp.*(..))")
public void after(){
System.out.println("方法执行后");
}
}
提示: 如果在其中增加环绕,那么执行顺序则是:环绕前-before-方法-after-环绕后。
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.yun.service.UserServiceImp"/>
<bean id="annotationPointCut" class="com.yun.mylog.AnnotationPointCut"/>
<!-- 开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>