引入
为了将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,Spring提供了面向切面的编程方式,也称Spring AOP。它有效地减少了系统间的重复代码,实现了模块间的松耦合。
简介
AOP全称为Aspect Oriented Programming,即面向切面编程。AOP采用横向抽取机制,主要体现在事务处理,日志管理、权限控制、异常处理等方面,使开发人员在编写业务逻辑时可以专心于核心业务,提高了代码的可维护性。
目前最流行的AOP框架有两个,分别为Spring AOP和AspectJ。Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强的代码。AspectJ是一个基于Java语言的AOP框架,提供了一个专门的编译器,在编译时提供横向代码的织入。
AOP术语
AOP的专业术语包括Joinpoint、PointCut、Advice、Target、Weaving、Proxy和Aspect,各名词解释如下:
- Joinpoint(连接点):类中的方法。
- Pointcut(切入点):是指要对哪些Joinpoint进行拦截,即被拦截的连接点。
- Advice(通知):在某个特定的Pointcut上需要执行的动作。如日志记录、权限验证等。
- Target(目标):是指代理的对象。
- Weaving(织入):是指把增强代码应用到目标上,生成代理对象的过程。
- Proxy(代理):是指生成的代理对象。
- Aspect(切面):是指切入点和通知的结合。
五种通知
- before:前置通知。目标方法执行前执行。
- after:后置通知。目标方法执行后执行。
- after returning:后置返回通知。目标方法返回时执行。
- after throwing:异常通知。目标方法抛出异常时执行。
- around:环绕通知。在目标函数执行中执行,可控制目标函数是否执行。
示例
public class HelloWorld {
public void sayHelloWorld(){
System.out.println("Hello World!");
}
public void sayHelloSpring(){
System.out.println("Hello Spring!");
}
}
public class MyAspect {
public void myBefore(JoinPoint joinPoint){
System.out.println("方法执行前......");
}
public void myAfter(JoinPoint joinPoint){
System.out.println("方法执行后......");
}
}
配置文件
<?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">
<!-- 1.目标类 -->
<bean id="helloWorld" class="cn.jujianfei.project.demo2.HelloWorld"></bean>
<!-- 2.切面 -->
<bean id="myAspect" class="cn.jujianfei.project.demo2.MyAspect"></bean>
<!-- 3.aop配置 -->
<aop:config>
<aop:aspect ref="myAspect">
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut id="myPointcut"
expression="execution(* cn.jujianfei.project.demo2.HelloWorld.*(..))"></aop:pointcut>
<!-- 3.2 关联通知Advice和切入点Pointcut-->
<aop:before method="myBefore" pointcut-ref="myPointcut"></aop:before>
<aop:after method="myAfter" pointcut-ref="myPointcut"></aop:after>
</aop:aspect>
</aop:config>
</beans>
单元测试
@Test
public void test5(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("demo1.xml");
HelloWorld hello = (HelloWorld)applicationContext.getBean("helloWorld");
hello.sayHelloWorld();
hello.sayHelloSpring();
}
打印结果
Execution函数
配置文件中的execution函数用来匹配切入点。语法结构为(其中,访问修饰符、类全路径、异常类型可选):
execution([访问修饰符] [返回值类型] [类全路径].[方法名](参数类型) 异常类型)
官方文档语法结构:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
通配符的含义
..
:匹配方法定义中任意数量的参数,此外还可以匹配类定义中任意数量的包。*
:匹配任意数量的字符。
示例
//匹配任意返回值,任意名称,任意参数的公共方法
execution(public * *(..))
//匹配以set开头,参数为int类型,任意返回值的方法
execution(* set*(int))
//匹配在service包或其子包下的任意方法
execution(* com.xyz.service..*.*(..))
//匹配UserDaoImpl类中的所有方法
execution(* com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中的所有公共的方法
execution(public * com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中的所有返回值为int类型的公共方法
execution(public int com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中第一个参数为int类型的所有公共的方法
execution(public * com.zejian.dao.UserDaoImpl.*(int , ..))
基于注解的Spring AOP
@Component
public class HelloWorld {
public void sayHelloWorld(){
System.out.println("Hello World!");
}
public void sayHelloSpring(){
System.out.println("Hello Spring!");
}
}
@Aspect
@Component
public class MyAspect {
@Pointcut("execution(* cn.jujianfei.project.demo3.HelloWorld.*(..))")
private void myPointCut(){}
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint){
System.out.println("方法执行前......");
}
@After("myPointCut()")
public void myAfter(JoinPoint joinPoint){
System.out.println("方法执行后......");
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:demo2.xml")
public class MyTest {
@Autowired
private HelloWorld helloWorld;
@Test
public void test(){
helloWorld.sayHelloWorld();
helloWorld.sayHelloSpring();
}
}
打印结果不变。
参考资料: https://blog.csdn.net/nvd11/article/details/51835717
参考资料: https://blog.csdn.net/javazejian/article/details/56267036
参考资料: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop