AOP学习笔记

一、AOP框架的基本介绍

1.1 AOP编程的优点

  1. 我们在使用过程中可以将对象之间的依赖关系交由Spring进行控制,从而做到大幅度的降低代码的耦合度;
  2. 通过AOP(面向切面编程)做到了对于OOP很难做到的事情,比如打印日志、写测试类;

1.2 AOP编程的介绍

AOP是英文Aspect Oriented Programming的缩写,也就是面向切面编程。Java最重要的思想就是面向对象的编程思想,万物皆对象,面向切面编程与之恰好是互补的关系,其中OOP理解为纵向编程,而AOP是横向编程。

1.3 AOP与OOP 的区别

  1. OOP 是纵向结构,AOP 是横向结构
  2. OOP 注重业务逻辑单元的划分,AOP 偏重业务处理过程中的某个步骤或阶段

我们在设计对象的时候一般都是纵向思维,如果这个时候考虑这些不同类对象的共性,不仅会增加设计的难度和复杂性,还会造成类的接口过多而难以维护,以至于对现有的对象动态增加一些方法的时候就会非常困难。这个时候,就需要用上AOP了。AOP就可以很好地解决以上的问题,它除了这种纵向分类之外,还从横向的角度去观察这些对象,无需再去到处调用 LogUtils 了,声明哪些地方需要打印日志,这个地方就是一个切面,AOP 会在适当的时机为你把打印语句插进切面。

2、 AOP的应用场景

  1. 参数校验和判空

系统之间在进行接口调用时,往往是有入参传递的,入参是接口业务逻辑实现的先决条件,有时入参的缺失或错误会导致业务逻辑的异常,大量的异常捕获无疑增加了接口实现的复杂度,也让代码显得雍肿冗长,因此提前对入参进行验证是有必要的,可以提前处理入参数据的异常,并封装好异常转化成结果对象返回给调用方,也让业务逻辑解耦变得独立。

  1. 处理权限控制

避免到处都是申请权限和处理权限的代码

  1. 无痕埋点

所谓的”无痕埋点”,其实就是通过技术手段,无差别的记录用户在产品中的行为

  1. 安全控制

比如全局的登录状态流程控制。

  1. 日志记录

  2. 事件防抖

防止View被连续点击触发多次事件

  1. 性能统计

检测方法耗时其实已经有一些现成的工具,比如 trace view。痛点是这些工具使用起来都比较麻烦,效率低下,而且无法针对某一个块代码或者某个指定的sdk进行查看方法耗时。可以采用 AOP 思想对每个方法做一个切点,在执行之后打印方法耗时。

  1. 事务处理

声明方法,为特定方法加上事务,指定情况下(比如抛出异常)回滚事务

  1. 异常处理

替代防御性的 try-Catch。

  1. 缓存

缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。

  1. 软件破解

使用修改软件的验证类的判断逻辑。

  1. 热修复

AOP 可以让我们在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。

三、AOP代码流程

第一步:导入依赖包

	<dependencies>
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
	</dependencies>

第二步:准备Target

public class UserServiceImpl implements UserService {
     
    private UsersDao usersDao;

    public void setUsersDao(UsersDao usersDao) {
     
        System.out.println("setUsersDao");
        this.usersDao = usersDao;
    }

    public int insetrUser1(Users users) {
     
        System.out.println("UserServiceImpl");
        usersDao.insetrUser1(users);
        return 0;
    }
}

第三步:准备Advice

多种advice

1、前置Advice

前置额外功能:MethodBeforeAdvice 。前置额外功能会在目标核心功能执行之前执行

public void before(JoinPoint joinPoint){
     
        System.out.println("日志开始");
        System.out.println(new Date()+"切点对象信息:"+joinPoint.getTarget().getClass().getSimpleName());
        System.out.println("方法信息:"+joinPoint.getSignature());
        System.out.println("参数信息:"+joinPoint.getArgs());
    }
 <bean id="myaop" class="com.xzk.Util.MyAop"></bean>
    <aop:config>
        <aop:pointcut id="mypc" expression="execution(public void com.xzk.service.UserService.insetrUser1())"/>
        <aop:aspect ref="myaop">
            <!--写入需要增强的方法-->
            <aop:before method="before" pointcut-ref="mypc"/>
        </aop:aspect>
    </aop:config>

2、后置Advice

后置额外功能:AfterReturningAdvice。后置额外功能会在目标核心功能执行之后执行

public void after(){
     
        System.out.println("日志结束");
    }
------------------------------------------------------------------------
    <bean id="myaop" class="com.xzk.Util.MyAop"></bean>
    <aop:config>
        <aop:pointcut id="mypc" expression="execution(public void com.xzk.service.UserService.insetrUser1())"/>
        <aop:aspect ref="myaop">
            <!--写入需要增强的方法-->
            <aop:after-returning method="after" pointcut-ref="mypc"/>
        </aop:aspect>
    </aop:config>

3、环绕Advice

环绕额外对象:MethodInterceptor。环绕额外功能会在目标核心功能执行前后都执行

public void myaroud(ProceedingJoinPoint joinPoint){
     
        System.out.println("环绕开始");
        try {
     
            joinPoint.proceed(); //调取目标方法
        } catch (Throwable throwable) {
     
            throwable.printStackTrace();
        }
        System.out.println("环绕结束");
    }
------------------------------------------------------------------------
    <aop:around method="myaroud" pointcut-ref="mypc"/>

4、异常Advice

异常额外对象:ThrowAdvice。前置额外功能会在目标核心功能执行之前执行(相当于try…catch)

   public void myex(){
     
        System.out.println("异常增强");
    }
------------------------------------------------------------------------
	<aop:after-throwing method="myex" pointcut-ref="mypc"/>

5、最终Advice

最终额外对象:在核心执行之后(即使核心出现了异常,依然执行额外,相当于try…catch…finally中的finally)。后置额外功能会在目标核心功能执行之后执行

public void aftera(){
     
        System.out.println("最终增强");
    }
------------------------------------------------------------------------
	<aop:after method="aftera" pointcut-ref="mypc"/>

第四步:编织 Weave

所谓编织,即,将Target和Advice组装形成代理,整个组装过程由Spring来管理,我们只需要做出配置,告知Spring需要组装谁即可

    <!-- id="(唯一的)对象名" class="类的完整路径"-->
    <bean id="udao" class="com.xzk.dao.impl.UserDaoImpl"></bean>

    <bean id="uservice" class="com.xzk.service.impl.UserServiceImpl">
        <property name="usersDao" ref="udao"></property>
    </bean>
    <bean class="com.xzk.bean.Users" p:users="馒头"></bean>

第五步:测试

编写一个测试类

 public static void main(String[] args) {
     
        // 1.加载配置文件
        ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");
        // 2.通过getBean获得指定对象
        UserService uservice = (UserService) app.getBean("uservice");
        uservice.insetrUser1(new Users());
    }

你可能感兴趣的:(萌新刚上道,aop,设计模式)