请选择 进入手机版 | 继续访问电脑版
MSIPO技术圈 首页 IT技术 查看内容

spring 详解六 AOP

2023-07-13

AOP概念

AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华,OOP是纵向对事物的抽象,一个对象包含属性信息和动态的方法信息等,而AOP是横向对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而这种思想叫做界面编程

相关核心概念

名称      说明
Target目标对象,被增强方法所在的对象
proxy增强后的代理对象,实际调用的对象
joinpoint目标对象中可以被增强的方法
pointcut目标对象中实际被增强的方法
advice增强部分代码逻辑 就是通知
Aspect增强部分和切入点的组合
weaving        将通知和切入点动态组合的过程

通知分类

通知        说明
before(前置通知)在切点方法之前执行增强方法
after(后置通知)在切点方法执行之后执行增强方法
after-returning(返回后通知)在切点方法返回之后执行增强方法
after-throwing(抛出异常通知)在切点方法抛出异常之后执行增强方法
around(环绕通知)通知方法封装切点方法环绕执行

Spring AOP两种使用方式

使用Spring自带的AOP

配置通知时需实现org.springframework.aop包下的一些接口

  • 前置通知:MethodBeforeAdvice
  • 后置通知:AfterReturningAdvice
  • 环绕通知:MethodInterceptor
  • 异常通知:ThrowsAdvice
public class LogAdvice implements MethodBeforeAdvice, AfterReturningAdvice,MethodInterceptor {
 
    @Override
 
    public void before(Method method, Object[] objects, Object target) throws Throwable {
 
        //前置通知
 
    }
 
 
 
    @Override
 
    public void afterReturning(Object result, Method method, Object[] objects, Object target) throws Throwable {
 
        //后置通知
 
    }
 
     @Override
 
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
 
        //环绕通知
 
        //目标方法之前执行
 
        methodInvocation.proceed();   //目标方法
 
 
 
        //目标方法之后执行
 
        return resultVal;
 
    }
 
}

 <bean id="userServiceBean" class="com.apesource.service.impl.UserServiceImpl"/>

 <bean id="logAdviceBean" class="com.apesource.log.LogAdvice"/>
 
<bean id="createMethodPointcutBean"     class="org.springframework.aop.support.JdkRegexpMethodPointcut">
 
    <!--注入正则表达式:描述那些方法为切入点-->
 
    <property name="pattern" value=".*creat.*"/>
 
</bean>

Advisor

Advisor(高级通知) = Advice(通知) + Pointcut(切入点)

<bean id="performanceAdvisorBean" class="org.springframework.aop.support.DefaultPointcutAdvisor">
 
        <!--注入切入点-->
 
        <property name="pointcut" ref="createMethodPointcutBean"/>
 
 
 
        <!--注入通知-->
 
        <property name="advice" ref="logAdviceBean"/>
 
    </bean>

使用Aspectj实现切面 

<!--业务组件bean-->
 
<bean id="userServiceBean" class="com.apesource.service.impl.UserServiceImpl"/>
 
 
 
<!--日志Aspect切面-->
 
<bean id="logAspectjBean" class="com.apesource.log.LogAspectj"/>
 
 
 
<!--使用Aspectj实现切面,使用Spring AOP进行配置-->
 
<aop:config>
 
    <!--配置切面-->
 
    <!--注入切面bean-->
 
    <aop:aspect ref="logAspectjBean">
 
        <!--定义Pointcut:通过expression表达式,来查找 特定的方法(pointcut)-->
 
        <aop:pointcut id="pointcut"
 
                     expression="execution(* com.apesource.service.impl.*.create*(..))"/>
 
 
 
        <!--配置"前置通知"-->
 
        <!--在pointcut切入点(serviceMethodPointcut)查找到 的方法执行"前",
            来执行当前logAspectBean的doBefore-->
 
        <aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
 
 
 
        <!--配置“后置通知”-->
 
        <!--returning属性:配置当前方法中用来接收返回值的参数名-->
 
        <aop:after-returning returning="returnVal" 
 
                             method="afterReturningAdvice" pointcut-ref="pointcut"/> 
 
        <aop:after method="afterAdvice" pointcut-ref="pointcut"/>
 
        
 
        <!--配置"环绕通知"-->
 
        <aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
 
        
 
        <!--配置“异常通知”-->
 
        <!--throwing属性:配置当前方法中用来接收当前异常的参数名-->
 
        <aop:after-throwing throwing="ex" method="throwAdvice" pointcut-ref="pointcut"/>
 
    </aop:aspect>
 
 
 
</aop:config>

Spring AOP的实现原理

Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理。

JDK动态代理:Spring AOP的首选方法。每当目标对象实现一个接口时,就会使用JDK动态代理。目标对象必须实现接口
CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理

JDK动态代理基于接口,CGLIB代理基于类

spring注解实现AOP 

package com.test.aop2;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


/**
 * 注解方式声明aop
 * 1.用@Aspect注解将类声明为切面(如果用@Component("")注解注释为一个bean对象,那么就要在spring配置文件中开启注解扫描,<context:component-scan base-package="com.cjh.aop2"/>
 *      否则要在spring配置文件中声明一个bean对象)
 * 2.在切面需要实现相应方法的前面加上相应的注释,也就是通知类型。
 * 3.此处有环绕通知,环绕通知方法一定要有ProceedingJoinPoint类型的参数传入,然后执行对应的proceed()方法,环绕才能实现。
 */
@Component("annotationTest")
@Aspect
public class AnnotationTest {
    //定义切点
    @Pointcut("execution(* *.saying(..))")
    public void sayings(){}
    /**
     * 前置通知(注解中的sayings()方法,其实就是上面定义pointcut切点注解所修饰的方法名,那只是个代理对象,不需要写具体方法,
     * 相当于xml声明切面的id名,如下,相当于id="embark",用于供其他通知类型引用)
     * <aop:config>
        <aop:aspect ref="mistrel">
            <!-- 定义切点 -->
            <aop:pointcut expression="execution(* *.saying(..))" id="embark"/>
            <!-- 声明前置通知 (在切点方法被执行前调用) -->
            <aop:before method="beforSay" pointcut-ref="embark"/>
            <!-- 声明后置通知 (在切点方法被执行后调用) -->
            <aop:after method="afterSay" pointcut-ref="embark"/>
        </aop:aspect>
       </aop:config>
     */
    @Before("sayings()")
    public void sayHello(){
        System.out.println("注解类型前置通知");
    }
    //后置通知
    @After("sayings()")
    public void sayGoodbey(){
        System.out.println("注解类型后置通知");
    }
    //环绕通知。注意要有ProceedingJoinPoint参数传入。
    @Around("sayings()")
    public void sayAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("注解类型环绕通知..环绕前");
        pjp.proceed();//执行方法
        System.out.println("注解类型环绕通知..环绕后");
    }
}

相关阅读

热门文章

    手机版|MSIPO技术圈 皖ICP备19022944号-2

    Copyright © 2024, msipo.com

    返回顶部