11-Spring-AOP-通过案例理解AOP

starrylsi
2024-09-12 / 0 评论 / 14 阅读 / 正在检测是否收录...

目标: 通过加减乘除的这个案例理解AOP
掌握: 未使用AOP时的代码和使用了AOP编程的代码

概念

AOP是面向切面编程。全称:Aspect Oriented Programming

面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。

1. 一个简单计算数功能加日记案例理解AOP的工作

package top.starrylsi.caculate;

public interface Caculate {
    public int add(int x,int y);
    
    public int sum(int x,int y);
    
    public int mul(int x, int y);
    
    public int div(int x,int y);
}
package top.starrylsi.caculate;

public class Caculator implements Caculate{

    @Override
    public int add(int x, int y) {
        // TODO Auto-generated method stub
        return x+y;
    }

    @Override
    public int sum(int x, int y) {
        // TODO Auto-generated method stub
        return x-y;
    }

    @Override
    public int mul(int x, int y) {
        // TODO Auto-generated method stub
        return x*y;
    }

    @Override
    public int div(int x, int y) {
        // TODO Auto-generated method stub
        return x/y;
    }

}

1.1 原始方法统一日记处理

  • 把日记的内容封装到一个类去中集中处理。
  • 缺点:这种方式的不足之处是,每有一个需要加日记的类,都需要到类的代码中去添加日记功能代码。无法做到所有对象都统一处理。

1. 编写一个日记处理工具类

package top.starrylsi.utils;

import java.util.Arrays;

public class LogUtils {
    public static void logBefore(String method,Object ...params) {
        System.out.println("方法"+method+"参数�:"+Arrays.toString(params));
    }
    
    public static void logAfter(String method,Object result) {
        System.out.println("方法"+method+"结果:"+result);
    }
}    

2. 修改原来Calculator中的日记代码

@Override
public int add(int x, int y) {
    LogUtils.logBefore("add",x,y);
    
    int result = x +y;
    
    LogUtils.logBefore("add",x,y);
    
    return result;
}

1.2 使用jdk代理实现日记

解释: 通过反射创建了一个新的caculate对象,里面有原本的功能也加了额外的功能((Caculate)Proxy.newProxyInstance(loader, interfaces, new JDKProxyHandler(caculate));)
优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。
缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。
思路:完成代理我们是使用了两个类(top.starrylsi.proxy下的 JDKProxyFactory,JDKProxyHandler),JDKProxyFactory用来生成代理对象的.JDKProxyHandler是JDKProxyFactory中的一个参数,是专门用来实现操作逻辑的.

1. 编写 JDKProxyFactory代码

  • 关键点1: Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h))
  • 关键点2: 调用JDKProxyHandler

package top.starrylsi.proxy;

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

import top.starrylsi.caculate.Caculate;

public class JDKProxyFactory {
    public static Caculate getProxy(Caculate caculate) {
        //1. 获取被代理类的类加载器
        ClassLoader loader = caculate.getClass().getClassLoader();
        
        //2. 获取被代理对象的父接口
        Class<?> [] interfaces = caculate.getClass().getInterfaces();    
        
        //3. 创建代理对象
        return (Caculate)Proxy.newProxyInstance(loader, interfaces, new JDKProxyHandler(caculate));
    }
}

2. 编写 JDKProxyHandler代码 (top.starrylsi.proxy)

  • 关键: 实现InvocationHandler的方法
package top.starrylsi.proxy;

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

import top.starrylsi.caculate.Caculate;
import top.starrylsi.utils.LogUtils;

public class JDKProxyHandler implements InvocationHandler{
    private Caculate caculate;
    
    public JDKProxyHandler(Caculate caculate) {
        this.caculate = caculate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1. 获取方法名
        String methdName = method.getName();
        
        //2. 调用日志
        LogUtils.logBefore(methdName, args);
        
        //3. 调用方法 并获取返回值
        Object result = method.invoke(caculate, args);
        
        //4. 调用日志之后的功能
        LogUtils.logAfter(methdName, result);
        return null;
    }
}

3. 测试

关键点: 知道如何调用

// 调用的关键点
private Caculate caculateProxy = JDKProxyFactory.getProxy(caculate);
package top.starrylsi.test;


import org.junit.jupiter.api.Test;

import top.starrylsi.caculate.Caculate;
import top.starrylsi.caculate.Caculator;
import top.starrylsi.proxy.JDKProxyFactory;

class CaculateTests {

    private Caculate caculate = new Caculator();
    private Caculate caculateProxy = JDKProxyFactory.getProxy(caculate);
    @Test
    public void testCaculator() {
        int result = caculate.add(5, 10);
        System.out.println(result);
    }
    
    @Test
    public void testProxy() {
        caculateProxy.add(2, 4);
    }
}
0

评论 (0)

取消