2023-01-18

一、AOP前奏-代理模式

1、手动实现动态代理环境搭建

(1)基于接口实现动态代理:JDK动态代理

(2)基于继承实现动态代理:Cglib、javassist动态代理

2、实现动态代理的步骤

(1)一个类:Proxy

①概述:Proxy代理类的基类(类似于Object)

②作用:newProxyInstance():创建代理对象

(2)一个接口:InvocationHandler

①概述:实现“动态织入效果”的关键接口

②作用:invoke(),执行invoke()实现动态织入效果

3、手动实现动态代理关键步骤

注意:代理对象与实现类(目标对象)是“兄弟”关系,不能相互转换

(1)创建类(为实现创建代理对象工具类)

(2)提供属性(目标对象:实现类)

(3)提供方法(创建代理对象)

(4)提供有参构造器(避免目标为空)

4、实例代码

(1)开启组件

<?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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--    开启组件扫描-->
    <context:component-scan base-package="com.hh"></context:component-scan>
</beans>

(2)接口

public interface Calc {
    /**
     * 加法
     * @param a
     * @param b
     * @return
     */
    int add(int a,int b);
    /**
     * 解放
     * @param a
     * @param b
     * @return
     */
    int sub(int a,int b);
    /**
     * 乘法
     * @param a
     * @param b
     * @return
     */
    int mul(int a,int b);
    /**
     *除法
     * @param a
     * @param b
     * @return
     */
    int div(int a,int b);
}

(3)实现类

@Component
public class CalcImpl implements Calc {
    @Override
    public int add(int a, int b) {
        int result = a + b;
        return result;
    }
    @Override
    public int sub(int a, int b) {
        int result = a - b;
        return result;
    }
    @Override
    public int mul(int a, int b) {
        int result = a*b;
        return result;
    }
    @Override
    public int div(int a, int b) {
        int result = a/b;
        return result;
    }
}

(4)日志类

public class MyLogging {
    /**
     * 方法之前
     */
    public static void beforeMethod(String methodName,Object[] arg){
        System.out.println("==>Calc中"+methodName+"方法(),参数:"+ Arrays.toString(arg));
    }
    /**
     * 方法之后
     */
    public static void afterMethod(String methodName,Object rs){
        System.out.println("==>Calc中"+methodName+"方法(),结果:"+rs);
    }
}

(5)代理类

public class MyProxy {
    /**
     * 目标对象(目标客户)
     */
    private Object target;
    public MyProxy(Object target){
        this.target = target;
    }
    /**
     * 获取目标对象的代理对象
     * @return
     */
    public Object getProxyObject(){
        Object proxyObj = null;
        /*
        ClassLoader loader:类加载器,目标对象类加载器
        Class<?>[] interfaces,目标对象实现接口,目标对象实现所有接口
        InvocationHandler h
        */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        //创建代理对象
        proxyObj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            //执行invoke()实现动态织入效果
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取方法名(目标对象)
                String methodName = method.getName();
                //执行目标方法之前,添加日志
                MyLogging.beforeMethod(methodName,args);
                //触发目标方法
                Object rs = method.invoke(target, args);
                //执行目标方法之后,添加日志
                MyLogging.afterMethod(methodName,rs);
                return rs;
            }
        });
        return proxyObj;
    }
}

(6)测试类

@ContextConfiguration(locations = "classpath:applicationContext_beforeAop.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestBeforeAop {
    @Autowired
    private Calc calc;
    @Test
    public void testBeforeAop(){
        int add = calc.add(1,2);
        System.out.println("add = " + add);
    }
    @Test
    public void testBeforeAop2(){
        //目标对象
        Calc calc = new CalcImpl();
        //代理工具类
        MyProxy myProxy = new MyProxy(calc);
        //获取代理对象
        Calc calcProxy = (Calc)myProxy.getProxyObject();
        //测试
        int add = calcProxy.add(1, 2);
        int div = calcProxy.div(2, 1);
        System.out.println("add = " + add);
        System.out.println("div = " + div);
    }
}