Java动态代理

案例

模拟企业业务功能开发,并完成每个功能的性能统计

需求:

  • 模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。

分析:

  • 定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
  • 定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。
  • 定义测试类,创建实验类对象,调用方法。

UserService:

package CC.Proxy;

/**
 * 模拟用户业务功能
 */
public interface UserService {
    String login(String loginName,String passWord);
    void selectUsers();
    boolean deleteUsers();
}

UserviceImpl:

package CC.Proxy;

public class UserServiceImpl implements UserService{

    @Override
    public String login(String loginName, String passWord) {
        long startTimer = System.currentTimeMillis();
            try {
                Thread.sleep(1000);
                if("admin".equals(loginName) && "1234".equals(passWord)){
                    return "success";
                }
                return "登录名和密码可能有毛病";
            } catch (Exception e){
                e.printStackTrace();
                return "error";
            } finally {
                long endTimer = System.currentTimeMillis();
                System.out.println("login方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
         }
    }

    @Override
    public void selectUsers() {
        long startTimer = System.currentTimeMillis();
        System.out.println("查询了100个用户数据!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTimer = System.currentTimeMillis();
        System.out.println("selectUsers方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
    }

    @Override
    public boolean deleteUsers() {
        long startTimer = System.currentTimeMillis();
        try {
            System.out.println("删除了100个用户数据!");
            Thread.sleep(500);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }finally {
            long endTimer = System.currentTimeMillis();
            System.out.println("deleteUsers方法耗时: " + (endTimer-startTimer)/1000.0 + "s");
        }
    }
}

Test:

package CC.Proxy;

public class Test {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        System.out.println(userService.login("admin","1234"));
        userService.selectUsers();
        System.out.println(userService.deleteUsers());
    }
}
/**
login方法耗时: 1.011s
success
查询了100个用户数据!
selectUsers方法耗时: 2.007s
删除了100个用户数据!
deleteUsers方法耗时: 0.514s
true
*/

本案例存在哪些问题?

业务对象的每个方法 都要进行性能统计,存在大量重复的代码。

使用动态代理解决问题

动态代理

  • 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的 。

关键步骤

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)

  • 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

1645524964926.png
1645529622791.png

把这里创立的对象传入代理中,返回一个代理对象回来

ProxyUtil代码:

package CC.Proxy;

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

/**
 * public static Object newProxyInstance(ClassLoader loader,Class<?>[]  interfaces,InvocationHandler h)
 * 参数一: 类加载器,负责加载代理
 * 参数二: 获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行的代理
 * 参数三: 代理的核心处理逻辑
 */


public class ProxyUtil {
    /**
     * 生成业务对象的代理对象
     * @param obj
     * @return
     */
    public static UserService getProxy(UserService obj) {
        //返回了一个代理对象
        return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //参数一: 代理对象本身
                        //参数二: 正在被代理的方法
                        //参数三: 被代理方法,应该传入的参数
                        long startTimer = System.currentTimeMillis();
                        //马上触发方法的真正执行。(触发真正的业务功能)
                        Object result = method.invoke(obj,args);

                        long endTimer = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时: " + (endTimer-startTimer)/1000.0 + "s");


                        //把业务功能方法执行的结果返回给调用者
                        return result;
                    }
                });
    }
}
1645529344945.png

最后,在正常逻辑业务中,即可不再重复写性能统计的代码

package CC.Proxy;

public class UserServiceImpl implements UserService{

    @Override
    public String login(String loginName, String passWord) {

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if("admin".equals(loginName) && "1234".equals(passWord)){
            return "success";
        }
        return "登录名和密码可能有毛病";
    }

    @Override
    public void selectUsers() {
        System.out.println("查询了100个用户数据!");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean deleteUsers() {
        try {
            System.out.println("删除了100个用户数据!");
            Thread.sleep(500);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void updateUsers() {
        try {
            System.out.println("修改了100个用户!");
            Thread.sleep(2500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

想要增添其他方法的时候,只需写正常的业务逻辑代码,无需再写性能统计的代码。达到动态代理的效果

1645530110238.png