动态代理

发布时间 2023-06-30 16:04:02作者: lawranceCha

动态代理

准备案例、提出问题

案例:企业业务功能开发

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

需求

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

分析

①定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。

②定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。

③定义测试类,创建实现类对象,调用方法。

存在的问题

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

使用动态代理解决问题

动态代理概念

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

关键步骤

1.必须有接口,实现类要实现接口(代理通常是基于接口实现的)。
3.创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

public static void main(String[] args) {

        //1.把业务对象做成一个代理对象返回 代理对象类型也是UserService类型
        UserService userService=ProxyUtil.getProxy(new UserServicelmpl());

        System.out.println(userService.login("admin", "1234"));
        userService.selectUsers();
        System.out.println(userService.deleteUsers());
    }
-----------------------------------------------------
public class UserServicelmpl implements UserService{
    @Override
    public String login(String loginName, String password)  {


        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if ("admin".equals(loginName) && "1234".equals(password))
                return "登录成功!!!";
            else
                return "用户名或密码不正确!!!";

    }

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

    }

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

    }
}

----------------------------------------------------- 
    
/**
 public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces, InvocationHandler h)
 参数一:类加载器,负责加载代理类到内存中使用。
 参数二:获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行代理
 参数三:代理的核心处理逻辑
 */
public class ProxyUtil {
    /**
     * 生成业务对象的代理对象返回,代理对象的类型也是UserService类型
     * @param obj
     * @return
     */
    public static UserService getProxy(UserServicelmpl 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;

            }
        });
    }
}

动态代理优点

  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。

  • /**
     public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces, InvocationHandler h)
     参数一:类加载器,负责加载代理类到内存中使用。
     参数二:获取被代理对象实现的全部接口。代理要为全部接口的全部方法进行代理
     参数三:代理的核心处理逻辑
     */
    public class ProxyUtil {
        /**
         * 生成业务对象的代理对象返回,代理对象的类型也是UserService类型
         * @param obj
         * @return
         */
        public static <T>T getProxy(T obj) {
            //返回了一个代理对线对象
            return (T) 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;
    
                }
            });
        }
    }
    
  • 可以为被代理对象的所有方法做代理。

  • 可以在不改变方法源码的情况下,实现对方法功能的增强。

  • 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。