Java实践理解AOP

引言

  • 什么是AOP?(面试题),单纯回答面向切面编程不能令面试官满意,最好结合自己的理解。

AOP概述

  1. AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Obecj-Oriented Programming,面向对象编程)的补充。
  • 面向对象 — 纵向继承机制
  • 面向切面 — 横向抽取机制
  1. AOP编程的主要操作对象是切面(aspect),而切面用于模块化横切关注点(即公共功能Util)
  2. 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应用在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的类里—这样的类我们通常称之为“切面”。
  3. AOP的好处:(1)每个事务逻辑位于一个位置,代码不分散,便于维护和升级;(2)业务模块更简洁,只包含核心业务代码;
  4. AOP的实现就是依赖动态代理
  5. AOP图解
    在这里插入图片描述

AOP术语

  1. 横切关注点:从每个方法中抽取出来的同一类非核心业务
  2. 切面(Aspect):封装横切关注点信息的类,每个关注点体现为一个通知方法。
  3. 通知(Advice): 切面必须要完成的各个具体工作。(包括:前置通知、后置通知、返回通知、异常通知、环绕通知)
  4. 目标(Target): 被通知的对象。
  5. 代理(Proxy): 向目标对象应用通知之后创建的代理对象
  6. 连接点(Joinpoint): 横切关注点在程序代码中的具体实现,对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获异常后等。在应用程序中可以使用横纵两个坐标来定位一个具体的连接点:

在这里插入图片描述

手把手通过实践理解(简易计算器)

在这里插入图片描述

  1. 创建一个Java工程,然后自建conf文件夹(放xml配置文件),lib(放jar包)
  2. 需要导入的jar包
  1. conf配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.test"/>
    <aop:aspectj-autoproxy/>
</beans>
  • 业务逻辑层
package com.test.Service;

public interface MathService {
	//加减乘除
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

  • Impl实现层
package com.test.Impl;

import com.test.Service.MathService;
import org.springframework.stereotype.Service;
@Service
public class MathImpl implements MathService {

    private int result;

    public int add(int i, int j){
        this.result = i + j;
        return result;
    }
    public int sub(int i, int j){
        this.result = i - j;
        return result;
    }
    public int mul(int i, int j){
        this.result = i * j;
        return result;
    }
    public int div(int i, int j){
        this.result = i / j;
        return result;
    }
}

  • 所谓的横切关注点(公共功能:比如日志)
package com.test.Logger;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyLoggerAspect {


    @Before(value="execution(* com.test.Impl.MathImpl.*(..))")
    public void beforeMethod(){
        System.out.println("前置通知");
    }

    @After(value="execution(* com.test.Impl.MathImpl.*(..))")
    public void afterMethod(){
        System.out.println("后置通知");
    }

    @AfterReturning(value="execution(* com.test.Impl.MathImpl.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("method:"+methodName+"\tresult:" + result);
    }

    @AfterThrowing(value="execution(* com.test.Impl.MathImpl.*(..))", throwing = "ex")
    public void afterThrowingMethod(ArithmeticException ex){
        System.out.println("异常信息: " + ex);
    }

    /**
     *      这里是  环绕通知  相当于把前面都集成起来了,
     *      你可以试试把前面都注释掉,只用这一段
     *     @Around(value="execution(* com.test.Impl.MathImpl.*(..))")
     *     public Object aroundMethod(ProceedingJoinPoint joinPoint){
     *         try {
     *             System.out.println("前置通知");
     *             joinPoint.proceed();
     *         } catch (Throwable e) {
     *             e.printStackTrace();
     *             System.out.println("异常通知");
     *         }finally {
     *             System.out.println("后置通知");
     *         }
     *         //为什么这里不返回null?因为接收对象是Integer
     *         return -1;
     *     }
     */

}
  • 测试切面的优先级
package com.test.Logger;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)//@order的值越小优先级越高,默认值为Int的最大值
public class TestAspect {

    @Before(value="execution(* com.test.Impl.MathImpl.*(..))")
    public void before(){
        System.out.println("我优先级更高==》前置通知");
    }
}
  • 测试类
package com.test;

import com.test.Service.MathService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyProxyTest {

    public static void main(String[] args) {
        ApplicationContext ac =new ClassPathXmlApplicationContext("config.xml");
        MathService mathService = ac.getBean("mathImpl",MathService.class);
        mathService.div(4,2);
    }
}

【以上就是简易计算器的所有代码】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值