Spring框架——AOP面向切面编程

AOP概念

AOP:面向切面编程,一种编程范式,指导开发者去和组织程序结构。
AOP是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
简单来说, 就是在程序运行期间, 在不修改源码的情况下, 对正在运行的方法进行功能增强(添加或删除某些功能)。

AOP开发方式(三种)

  • XML方式
  • XML + 注解方式
  • 注解方式

AOP的作用和优点

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强。
优势:减少重复代码,提高开发效率,并且便于维护。

AOP开发步骤

  • 导入 AOP 相关坐标
<!--导入spring的context坐标,context依赖aop-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.5.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
  • 创建目标接口和目标类
//被增强类的接口
public interface TargetInterface {
    public void method();
}

//被增强类
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target running....");
    }
}
  • 创建增强类
//增强类
public class MyAspect {
    //前置增强方法
    public void before(){
        System.out.println("前置代码增强.....");
    }
}
  • 配置目标类和增强类
<!--配置目标类-->
<bean id="target" class="com.itheima.aop.Target"></bean>
<!--配置切面类-->
<bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
  • 配置织入关系
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--aop配置-->
    <aop:config>
        <!--配置切入点(要增强什么)-->
        <aop:pointcut id="pt" expression="execution(public void com.itheima.aop.Target.method())"/>
        <!--配置切面(怎么增强)-->
        <aop:aspect ref="myAdvice">
            <!--在指定Target的method方法之前,必须先执行myAdvice类的before方法-->
            <aop:before method="before" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
    
</beans>
  • 测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    
    @Autowired
    private TargetInterface target;
    
    @Test
    public void test1(){
        target.method();
    }
}

切入点表达式

execution(* *(..))
execution(* *..*(..))
execution(* *..*.*(..))
execution(public * *..*.*(..))
execution(public int *..*.*(..))
execution(public void *..*.*(..))
execution(public void com..*.*(..)) 
execution(public void com..service.*.*(..))
execution(public void com.itheima.service.*.*(..))
execution(public void com.itheima.service.User*.*(..))
execution(public void com.itheima.service.*Service.*(..))
execution(public void com.itheima.service.UserService.*(..))
execution(public User com.itheima.service.UserService.find*(..))
execution(public User com.itheima.service.UserService.*Id(..))
execution(public User com.itheima.service.UserService.findById(..))
execution(public User com.itheima.service.UserService.findById(int))
execution(public User com.itheima.service.UserService.findById(int,int))
execution(public User com.itheima.service.UserService.findById(int,*))
execution(public User com.itheima.service.UserService.findById(*,int))
execution(public User com.itheima.service.UserService.findById())
execution(List com.itheima.service.*Service+.findAll(..))

切入点表达式的配置方式

  • 配置公共切入点
<aop:config>
    <!--配置公共切入点-->
    <aop:pointcut id="pt1" expression="execution(* *(..))"/>
    <aop:aspect ref="myAdvice">
        <!--引用公共切入点-->
        <aop:before method="logAdvice" pointcut-ref="pt1"/>
    </aop:aspect>
</aop:config>
  • 配置局部切入点
<aop:config>
    <aop:aspect ref="myAdvice">
        <!--配置局部切入点-->
        <aop:pointcut id="pt2" expression="execution(* *(..))"/>
        <!--引用局部切入点-->
        <aop:before method="logAdvice" pointcut-ref="pt2"/>
    </aop:aspect>
</aop:config>
  • 直接配置切入点
<aop:config>
    <aop:aspect ref="myAdvice">
        <!--直接配置切入点-->
        <aop:before method="logAdvice" pointcut="execution(* *(..))"/>
    </aop:aspect>
</aop:config>

通知

  • 通知类型
名称标签说明
前置通知aop:before用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知aop:after-returning用于配置后置通知。指定增强的方法在切入点方法之后执行
异常通知aop:throwing用于配置异常抛出通知。指定增强的方法在出现异常时执行
最终通知aop:after用于配置最终通知。无论增强方式执行是否有异常都会执行
环绕通知aop:around用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行

通知获取参数数据的方式

第一种

通知获取参数数据

设定通知方法第一个参数为JoinPoint,通过该对象调用getArgs(方法,获取原始方法运行的参数数组

//所有的通知均可以获取参数
public void before(JoinPoint jp) throws Throwable {
	object[] args = jp.getArgs ();
}
第二种

设定切入点表达式为通知方法传递参数(锁定通知变量名)

原始方法

public void save (int param1,int param2){
	system.out.println ("user service running...");
}

AOP配置

<aop:aspect ref "myAdvice">
	<aop:pointcut id="pt" expression="execution(**(..)) &amp;&amp; args(a,b)"/>
	<aop:before method "before" pointcut-ref="pt"/>
</ aop:aspect>

通知类

public void before (int a,int b) {
	system.out.println("a=" + a);
	system.out.println("b=" + b);
}

通知获取返回值数据

设定返回值变量名

原始方法

public int save() {
	system.out.println("user service running.. .");
	return 100;
}

AOP配置

<aop:aspect ref "myAdvice">
	<aop:pointcut id="pt3" expression="execution(* *(..))"/>
	<aop:after-returning method="afterReturning" pointcut-ref="pt3" returning="ret"/>
</aop:aspect>

通知类

public void afterReturning(object ret) {
	system.out.println(ret);
}

适用于返回后通知(after-returning)

通知获取异常数据

设定异常对象变量名
原始方法

public void save() {
	system.out.println("user service running. ..");
	int i = 1 / 0;
}

AOP配置

<aop:aspect ref="myAdvice">
	<aop:pointcut id="pt4" expression="execution(* *(..))"/>
	<aop:after-returning method="afterThrowing" pointcut-ref= "pt4" throwing="t" />
</aop:aspect>

通知类

public void afterThrowing(Throwable t) {
	system.out.println(t.getMessage());
}

适用于返回后通知(after-throwing)

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页