AOP出现的背景
- 分离关注
分离关注就是将某一通用的需求功能从不相关的类中分离出来,使得很多类共享一个行为,当行为需求需要变化时,只需让该行为发生变化,不必修改其他类
设计模式追求的本质就是调用者与被调用者之间的解耦 - OOP
说到AOP,不得不提OOP,面向对象编程(三大特征:封装、继承、多态)是针对问题领域中以及处理过程中存在的实体及其属性和行为进行抽象和封装,从继承和多态的特性可以看出OOP的核心结构是纵向的,目的是获得清晰高效的逻辑单元划分 - AOP
AOP的全程是Aspect Oriented Programming,提供了另一个角度来完善OOP。核心思想就是将应用程序中业务逻辑部分与提供支持的通用服务部分进行分离
相关概念
-
横切关注点(Cross-cutting concerns)
横切关注点指的是在一个服务流程中与业务逻辑无关的系统服务逻辑。一个横切关注点可以横切多个对象。 -
切面(Aspect)
将散落在业务对象中的横切关注点独立出来在Spring中使用常规类来实现
切面的实现有两种方式:- 围绕通知(around advice)实现MethodInterceptor
- Advisor:Advice+Pointcut
-
连接点(Joinpoint)
程序执行过程中明确的点,在Spring中连接点就是一个方法调用 -
通知(Advice)
AOP框架在特定的连接点执行的动作。许多AOP框架包括Spring都是以拦截器为通知模型,维护一个围绕连接点的拦截器链 -
切入点(Pointcut)
连接点的匹配条件。通知和切入点表达式匹配的连接点进行关联 -
引入(Introduction)
添加防火或者字段到被通知的类。 -
目标对象(Target Object)
被通知或者切面的对象,或者称作被代理的对象 -
AOP代理(AOP Proxy)
AOP框架创建的包含通知的对象。
Spring动态代理技术:1. JDK动态代理:要求target对象必须实现接口 2. CGLIB:target可以不实现接口
-
织入(Weave)
通知被应用到对象之上的过程。
基于xml的AOP配置
- 首先用到spring框架就需要在pom.xml文件中加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="arithImpl" class="com.test.demo.ArithImpl"></bean>
<bean id="userDao" class="com.test.demo.UserDao"></bean>
<!-- 通知对象 -->
<bean id="myMethodBeforeAdvice" class="com.test.advice.MyMethodBeforeAdvice"></bean>
<bean id="myAfterReturningAdvice" class="com.test.advice.MyAfterReturningAdvice"></bean>
<bean id="myAroundAdvice" class="com.test.advice.MyAroundAdvice"></bean>
<bean id="myExceptionAdvice" class="com.test.advice.MyExceptionAdvice"></bean>
<!-- 切面-->
<bean id="myMethodBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="myMethodBeforeAdvice"></property>
<!-- 使用正则表达式来匹配类和方法名称
匹配 的完整类名和方法名 例如:com.test.demo.Arith.plus
. 匹配任意字符
? 匹配0个或者1个
+ 匹配1个或者多个
* 匹配0个或者多个
-->
<property name="patterns">
<array>
<!-- 匹配某个类中的plus方法 -->
<value>.+\.plus</value>
</array>
</property>
</bean>
<!-- 自动的将指定目标对象的代理对象创建出来
ioc容器中 目标对象bean的名字 对应的实际是代理对象
-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<array>
<value>arithImpl</value>
<value>*Dao</value>
</array>
</property>
<property name="interceptorNames">
<array>
<value>myExceptionAdvice</value>
<value>myAfterReturningAdvice</value>
<value>myMethodBeforeAdvisor</value>
<value>myAroundAdvice</value>
</array>
</property>
</bean>
</beans>
基于Java配置
package com.test;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.test.advice.MyMethodBeforeAdvice;
@Configuration
@ComponentScan({"com.test.advice","com.test.demo"})
public class AppConfig {
@Autowired
private MyMethodBeforeAdvice myMethodBeforeAdvice;
@Bean
public RegexpMethodPointcutAdvisor myMethodBeforeAdvisor() {
RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
advisor.setAdvice(myMethodBeforeAdvice);
advisor.setPatterns(new String[] {".+\\.plus"});
return advisor;
}
@Bean
public BeanNameAutoProxyCreator beanNameAuto() {
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
creator.setBeanNames(new String[] {"arithImpl","*Dao"});
creator.setInterceptorNames(new String[] {"myExceptionAdvice","myAfterReturningAdvice",
"myMethodBeforeAdvisor","myAroundAdvice"});
return creator;
}
}