victory的博客

长安一片月,万户捣衣声

0%

spring | 动态代理之数学计算器

动态代理-数学计算器

项目目录

1.要求
1)计算器能够执行加减乘除运算
2)日志:在程序执行期间追踪正在发生的活动
3)验证:希望计算器只能处理正数的运算

2.常规实现

**MathI.java**
package com.atguigu.proxy;

public interface MathI {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

MathImpl.java

package com.atguigu.proxy;

public class MathImpl implements MathI{

    @Override
    public int add(int i, int j) {
        System.out.println("method:add,arguments:" + i + "," + j);
        System.out.println("method:add,results:" + (i + j));
        return i + j;
    }
    
    @Override
    public int sub(int i, int j) {
        System.out.println("method:sub,arguments:" + i + "," + j);
        System.out.println("method:sub,results:" + (i - j));
        return i - j;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("method:mul,arguments:" + i + "," + j);
        System.out.println("method:mul,results:" + (i * j));
        return i * j;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("method:div,arguments:" + i + "," + j);
        System.out.println("method:div,results:" + (i / j));
        return i / j;
    }
}

常规实现方法存在的问题
①代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
②代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。

3.动态代理
MathI.java(与2中的代码相同)

MathImpl.java(2中的代码中去掉日志信息)

MyLogger.java(日志类)

ProxyUtil.java(代理类)

package com.atguigu.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyUtil{
    //代理模式:1、静态代理(代理对象真实存在,是自己写好的) 2、动态代理(动态生成代理对象,不需要自己写)
    private MathImpl mathImpl;//目标对象 目标对象类必须实现接口
    
    public ProxyUtil(MathImpl mathImpl) {
        super();
        this.mathImpl = mathImpl;
    }

    public Object getProxy(){
        //获取当前类的类加载器用来加载代理对象所属类
        ClassLoader loader = this.getClass().getClassLoader();//动态生成代理对象就需要动态代理类,代理类的执行需要类加载器
        //获取目标对象实现的所有接口的Class,代理类会和目标对象实现相同的接口,最终通过代理对象实现功能
        Class[] interfaces = mathImpl.getClass().getInterfaces();
        
        return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler(){

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //代理对象实现功能的方式
                try{
                    MyLogger.before(method.getName(), Arrays.toString(args));
                    Object result = method.invoke(mathImpl, args);//动态代理对象实现功能(调用目标对象的方法)
                    MyLogger.after(method.getName(), result);
                    return result;
                }catch (Exception e){
                    MyLogger.throwing();
                    e.printStackTrace();
                }finally{
                    System.out.println("哪都有我");
                }
                return null;
                
            }
        });
    }
}

Test.java(测试类)

package com.atguigu.proxy;

public class Test {

    public static void main(String[] args) {
//        MathI math = new MathImpl();
//        int result = math.add(1, 1);
//        System.out.println(result);
        ProxyUtil proxy = new ProxyUtil(new MathImpl());
        
        MathI math = (MathI)proxy.getProxy();
        
        int i = math.add(1, 1);
        System.out.println(i);
        
        int j = math.div(4, 0);
        System.out.println(j);
    }
}