AOP实现(一)——SpringBoot中AspectJ编程实现

一、什么是aop?

Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的
统一维护的一种技术
主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等。

二、SpringAOP的实现方式

下边这两种Spring都是支持的
2.1预编译
-AspectJ  完整的面向切面编程解决方案--》spring不是完整的解决方案,不过spring提供比较好的实现方式,当然spring是同时也是支持这种方式的,这也是一种常用的方式

2.2运行期间动态代理(JDK动态代理,CGLib动态代理)
-SpringAop,JbossAop

Spring的AOP使用纯java实现,无需特殊的编译过程,不需要控制类的加载器层次,目前只支持方法的执行的连接点(通知Spring Bean某个方法执行)
不是为了提供完整AOP实现;而是侧重于一种AOP于IOC容器之间的整合,SpringAOP不会AspectJ(完整的AOP解决方案)竞争

Spring没有使用AspectJ的时候,也可以通过如下方式实现AOP

Spring AOP 默认使用标准的JavaSE动态代理作为AOP代理,这使得任何接口(或者集合)都可以被代理
Spring AOP 中也可以使用CGLIB代理(如果一个业务对象没有实现一个接口)
有接口的:使用JDK的动态里
无接口的:使用CGLIB代理

三、SpringBoot中AspectJ 实现

AspectJ是一个AOP框架,由于SpringAOP的配置过于繁琐,因此使用了AspectJ依赖注解开发

1、Aspecj依赖,此处省略了Spring相关依赖

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
</dependency>

2.AspactJ框架常用注解

@PonitCut  // 声明切入点的注解
@Before       // 声明前置通知注解
@After           // 声明后置通知注解(原始方法执行正常或者非正常执行都会进入)
@AfterReturing    // 声明后置通知注解(原始方法必须正常执行)
@AfterThrowing    // 声明异常通知
@Around    // 环绕通知注解
3.实例

import com.pingan.haofang.standard.api.params.domain.ApiParams;
import com.pingan.haofang.standard.common.annotation.aspect.TableName;
import com.pingan.haofang.standard.common.context.ManageThreadContext;
import com.pingan.haofang.standard.common.context.ManageUser;
import com.pingan.haofang.standard.configmapping.domain.ConfigMapping;
import com.pingan.haofang.standard.configmapping.service.ConfigMappingService;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

@Aspect
@Component
public class AddConfigMappingAspect {
    private final Logger log = LoggerFactory.getLogger(AddConfigMappingAspect.class);


    @Autowired
    ConfigMappingService configMappingService;

    @Pointcut("@annotation(com.pingan.haofang.standard.common.annotation.aspect.AddConfigMapping)")
    public void addPoint() {

    }

    @AfterReturning(returning = "returnValue", pointcut = "addPoint()")
    public void doAfterReturning(Object returnValue) throws Throwable {
        Field field = null;
        List<ApiParams> paramsList = null;
        Long id = 0l;
        String tableName = "";
        if (returnValue instanceof List) {//1.0 返回值为集合
            paramsList = (List) returnValue;
            if (paramsList != null && paramsList.size() != 0) {
                TableName annotation0 = paramsList.get(0).getClass().getAnnotation(TableName.class);
                tableName = annotation0.name();
                log.info("tableName:" + tableName);
            }
        } else {
            //1.先利用反射获取拦截的返回值
            String objectName = returnValue.getClass().getSimpleName();
            field = returnValue.getClass().getDeclaredField("id");
            field.setAccessible(true);
            id = (Long) field.get(returnValue);
            TableName annotation = returnValue.getClass().getAnnotation(TableName.class);
            tableName = annotation.name();
            log.info("tableName:" + tableName + " id:" + id);
        }

        //2.获取当前版本和用户信息
        ManageUser currentUser = ManageThreadContext.getManageVisitor();

        if (paramsList != null && paramsList.size() != 0) {//当返回值为集合
            for (ApiParams apiParam : paramsList) {
                ConfigMapping configMapping = new ConfigMapping();
                configMapping.setObjectId(apiParam.getId());
                configMapping.setTableName(tableName);
                configMapping.setAppCode(currentUser.getCurrentApp());
                configMapping.setVersionNo(currentUser.getCurrentAppVersion());
                configMapping.setCreateTime(new Date());
                configMapping.setUpdateTime(new Date());
                configMappingService.insert(configMapping);
            }
        } else {
            //3.设置到配置映射表中
            if (!id.equals(0l)) {
                ConfigMapping configMapping = new ConfigMapping();
                configMapping.setObjectId(id);
                configMapping.setTableName(tableName);
                configMapping.setAppCode(currentUser.getCurrentApp());
                configMapping.setVersionNo(currentUser.getCurrentAppVersion());
                configMapping.setCreateTime(new Date());
                configMapping.setUpdateTime(new Date());

                configMappingService.insert(configMapping);
            }
        }
    }

}

改段代码完成的是在添加了拦截注解的方法上,拦截到方法返回值,将返回值id和当前用户信息保存到关系映射表中。

注意:

切入点不仅支持注解,也支持表达式,具体语法参照https://blog.csdn.net/zhengchao1991/article/details/53391244

要了解Spring配置文件方式实现,请参照https://blog.csdn.net/u014292162/article/details/52504633

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值