SpringAOP

AOP实现原理

Spring AOP 基于动态代理实现原理:
  ○ 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
  ○ 如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类);

AOP有关知识点(通知+aspect+pointcut)

AOP通知类型:
AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分
  前置通知(Before)
  后置通知(After)
  返回通知(After-returning)
  异常通知(After-throwing)
  环绕通知(Around)
SpringAOP_第1张图片

AOP重要的知识点。

AOP切面:切点+通知

SpringAOP+AspectJ实现步骤:
1.坐标
2.配置

 
       
            org.springframework
            spring-context
            5.3.28
       


       
            org.aspectj
            aspectjweaver
            1.9.7
       


   

AspectJ 切面:可以理解为要注入方法的所有通知

切点:到哪一个类的哪一个方法

AOP实现流程

1,正常的制作程序

 以上一篇的转账来说,事务管理注入到service的每一个方法当中。
2,将非共性功能开发到对应的目标对象类中,并制作成切入点方法,绿色的都可以当切入点

  @Override
    public void save(String name) {

        System.out.println("===>业务新增");
        int a = 10/0;//模拟异常
    }

    @Override
    public int delete(int num) {
        System.out.println("===>业务删除");
        return 0;
    }

    @Override
    public void findAll() {
        System.out.println("===>业务查询");
    }

3,将共性功能独立开发出来,制作成“通知”

事务的开启到AOP前置通知的地方

事务的提交可以放到AOP的返回通知的地方。

事务失败可以放到AOP的异常通知的地方。

事务关闭可以放到AOP的后置通知的地方。finally必须要执行的那个模块。

package com.apesource.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Date;

/**
 * @author 
 * @version 1.0
 * @since 2023/8/4
 */
public class LoggerUtil {
    //前置通知
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    public Object arroundMethod(ProceedingJoinPoint pjp){
        Object obj = null;

        try {
            //环绕通知---前置通知
            System.out.println("环绕通知---前置通知");
            Object[] objs = pjp.getArgs();
            obj = pjp.proceed(objs);
            //环绕通知---返回通知
            System.out.println("环绕通知---返回通知");
        } catch (Throwable throwable) {
            //环绕通知---异常通知
            System.out.println("环绕通知---异常通知");
            throwable.printStackTrace();
        } finally {
            //环绕通知---后置通知
            System.out.println("环绕通知---后置通知");
        }

        return obj;

    }


}

4.在配置文件中,声明“切入点”,该步骤可以让Spring定位到实体类的方法

切点表达式配置语法:
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
eg:
    execution(public void com.apesource.service.ServiceImp.findAll())
1.修饰符可以省略代表任意
    execution(返回值 包名称.类名称.方法名称(参数列表))
2.返回值可以使用“*”代表任意
    execution(* 包名称.类名称.方法名称(参数列表))
3.包名可以使用“*”代表任意名称
    execution(* *.*.*.类名称.方法名称(参数列表))
4.包名可以使用“..”代表任意个数
    execution(* *...类名称.方法名称(参数列表))
5.类名与方法名可以使用“*”代表任意
    execution(* *...*.*(参数列表))
6.参数列表可以使用".."代表任意个数任意类型
    execution(* *...*.*(..))
    如果有参数
        int======>int
        String===>java.lang.String

@Pointcut(value = "execution(* com.apesource.service.*.*(..))")
    public  void dian(){
    }

修饰符为任意,返回值任意, com.apesource.service下的所有类的所有方法。

5.在配置文件中,声明"切入点"与"通知"间的关系(含通知类型),即"切面"

@Component
@Aspect
public class LoggerUtil {


    @Pointcut(value = "execution(* com.apesource.service.*.*(..))")
    public  void dian(){
    }
    //前置通知
    @Before("dian()")
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
    @AfterReturning("dian()")
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
    @AfterThrowing("dian()")
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
    @After("dian()")
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    @Around("dian()")
    public Object arroundMethod(ProceedingJoinPoint pjp){

        Object obj = null;

        try {
            //环绕通知---前置通知
            System.out.println("环绕通知---前置通知");
            Object[] objs = pjp.getArgs();
            obj = pjp.proceed(objs);//proceed等于invoke方法
            //环绕通知---返回通知
            System.out.println("环绕通知---返回通知");
        } catch (Throwable throwable) {
            //环绕通知---异常通知
            System.out.println("环绕通知---异常通知");
            throwable.printStackTrace();
        } finally {
            //环绕通知---后置通知
            System.out.println("环绕通知---后置通知");
        }

        return obj;

    }

●运行阶段(AOP完成)=============spring帮我们做的
    ◆Spring容器加载配置文件,监控所有配置的“切入点”方法的执行
    ◆当监控到“切入点”方法被运行,使用“代理”机制,动态创建“目标对象”的“代理对象”,
 根据“通知类别”,在“代理对象”的对应位置将“通知”对应的功能“织入”,完成完整的代码逻辑并运行 

   
   


   



 





 


    
    

 test测试类。

package com.apesource.test;

import com.apesource.service.IService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 
 * @version 1.0
 * @since 2023/8/4
 */
public class Test01 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        IService service = (IService) applicationContext.getBean("serviceImp");
        service.save("今天周五");
//        service.delete(5);
//        service.findAll();

    }
}

你可能感兴趣的:(Spring,java,jvm,开发语言,spring)