012,Spring 面向切面,问题引入

V哥官网:http://www.vgxit.com

本博客对应视频教程:http://www.vgxit.com/course/23


面向切面-问题引入


1,概述

如果说IOC是Spring的核心,那么面向切面就是Spring最重要的功能之一了,面向切面的专业术语叫做AOP。在数据库事物中切面编程是广泛应用的。


2,AOP的概念和使用原因

我们就用我们的数据库编程来举例。比如,我们做了一个电商系统,我们要做一块使用账户余额支付的功能。这个功能一般情况下需要四个操作来支撑,分别是:1,商品库存减一。2,生成一个订单。3,账户余额扣款。4,生成一条交易记录。

按照没用Spring之前的操作我们可能会写如下伪代码:

商品扣库存;
if(商品库存扣成功) {
    生成订单;
    if(订单生成成功){
        账户余额扣款;
        if(账户余额扣款成功) {
            生成一条交易记录;
            if (交易记录生成成功) {
                提交事物;
            } else {
                事物回滚;
            }
        } else {
            事物回滚;
        }
    } else {
        事物回滚;
    }
} else {
    事物回滚;
}

对应的流程图如下:

从上面的情况,我们可以看出来我们代码编写得真的是非常非常的复杂。如果我们采用Spring Aop来管理事物,我们可以用如下流程图来代替。

我们通过上图可以看到,如果我们使用了Spring Aop来管理事物之后,我们的流程就会变得非常的简单。我们只需要做到如果数据库操作失败就直接抛出异常就行了。其他的,我们完全不用关心。那么我们思考一下我们如何才能做到这样的逻辑呢?

AOP是通过动态代理模式来管控哥哥对象操作的切换环境。包括日志,数据库事物等操作。让我们可以在反射原有对象方法正常返回,异常之前和返回后插入自己的逻辑代码的能力。在一些常用的流程中,比如数据库事物,AOP会提供默认的实现逻辑,也会提供一些简单的配置,程序员就能方便的修改默认的实现,从而达到符合真实引用要求的效果。提升代码的可读性,将开发集中在也业务逻辑上。


3,自己手写Aop:

自己实现AOP需要用到动态代理的知识,我们在这里就不会给大家再来介绍动态代理的知识了。如果大家没有这方面的知识,你需要去学习一下,看看老师之前讲的《简单设计模式入门》这门课程。我们这里手写AOP我们使用添加用户这样的逻辑来实现。

1,定义一个PO:

package com.vgxit.learn.spring.ktdm.myaop.po;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
    private Short gender;
}

2,创建对应的业务逻辑层的接口

package com.vgxit.learn.spring.ktdm.myaop.service;

import com.vgxit.learn.spring.ktdm.myaop.po.User;

public interface IUserService {
    void add(User user);
}

3,编写对应的业务逻辑层的实现类

package com.vgxit.learn.spring.ktdm.myaop.service.impl;

import com.vgxit.learn.spring.ktdm.myaop.po.User;
import com.vgxit.learn.spring.ktdm.myaop.service.IUserService;

public class UserService implements IUserService {
    @Override
    public void add(User user) {
        System.out.println("添加用户[" + user + "]到数据库");
    }
}

4,提供一个Interceptor拦截器接口,这个接口里面定义了再具体的业务方法之前,之后,正常返回,异常返回的时候我们要插入的代码:

package com.vgxit.learn.spring.ktdm.myaop.aop;

public interface Interceptor {
    //业务方法开始之前调用的代码
    void before(Object obj);
    //业务方法开始之后调用的代码
    void after(Object obj);
    //业务方法正常返回之后调用的代码
    void afterReturning(Object obj);
    //业务方法异常返回之后调用的代码
    void afterThrowing(Object obj);
}

5,编写Interceptor的具体实现类:

package com.vgxit.learn.spring.ktdm.myaop.aop;
public class TranInterceptor implements Interceptor {
    @Override
    public void before(Object obj) {
        System.out.println("获取数据库连接");
        System.out.println("开启事务");
    }

    @Override
    public void after(Object obj) {
        System.out.println("对应逻辑执行完成");
    }

    @Override
    public void afterReturning(Object obj) {
        System.out.println("提交事物");
    }

    @Override
    public void afterThrowing(Object obj) {
        System.out.println("事物回滚");
    }
}

6,实现动态代理工具类:

package com.vgxit.learn.spring.ktdm.myaop.proxy;

import com.vgxit.learn.spring.ktdm.myaop.aop.Interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil implements InvocationHandler {
    //被代理的对象
    private Object target;
    //对应的拦截器
    private Interceptor interceptor;

    //获取对应的代理对象
    public static <T> T getBean(T target, Interceptor interceptor) {
        ProxyUtil proxyUtil = new ProxyUtil();
        proxyUtil.target = target;
        proxyUtil.interceptor = interceptor;
        return (T) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), target.getClass().getInterfaces(), proxyUtil);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        //到时候要返回的数据
        Object result = null;
        boolean hasException = false;
        interceptor.before(target);
        try {
            //调用真实方法
            result = method.invoke(target, objects);
        } catch (Throwable e) {
            hasException = true;
        } finally {
            interceptor.after(target);
        }
        if (hasException) {
            interceptor.afterThrowing(target);
        } else {
            interceptor.afterReturning(target);
        }
        return result;
    }
}

7,测试代码:

package com.vgxit.learn.spring.ktdm.myaop.test;

import com.vgxit.learn.spring.ktdm.myaop.aop.Interceptor;
import com.vgxit.learn.spring.ktdm.myaop.aop.TranInterceptor;
import com.vgxit.learn.spring.ktdm.myaop.po.User;
import com.vgxit.learn.spring.ktdm.myaop.proxy.ProxyUtil;
import com.vgxit.learn.spring.ktdm.myaop.service.IUserService;
import com.vgxit.learn.spring.ktdm.myaop.service.impl.UserService;

public class MyAopTest001 {
    public static void main(String[] args) {
        IUserService target = new UserService();
        Interceptor interceptor = new TranInterceptor();
        IUserService userService = ProxyUtil.getBean(target, interceptor);
        User user = new User();
        user.setId(1);
        user.setName("李一桐");
        user.setGender((short) 2);
        userService.add(user);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

V哥学It

赏小的一个钱吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值