动态代理学习

文章介绍了Java中的动态代理机制,包括概念、优点以及如何创建代理对象。动态代理允许在不修改原有代码的情况下,通过代理对象对方法进行增强或添加额外操作。文中提供了两个案例,分别展示了对娱乐明星类和UserService接口的动态代理实现,强调了动态代理在灵活性和代码复用上的优势。
摘要由CSDN通过智能技术生成

1、简介

1.1 概念

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

1.2 动态代理的优点

  1. 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
  2. 可以为被代理对象的所有方法做代理。
  3. 可以在不改变方法源码的情况下,实现对方法功能的增强。
  4. 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。

2、如何创建代理对象

2.1 主要调用方法

  1. Java中代理的代表类是:java.lang.reflect.Proxy
    Proxy提供了一个静态方法,用于为对象产生一个代理对象返回。要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。
    Proxy.newProxyInstance(ClassLoader 加载器,Class<?> 接口,InvocationHandler h)
  2. newProxyInstance参数:
    一个类加载器(class loader)。
    一个Class对象数组,每个元素都是需要实现的接口。
    一个调用处理器

2.2 创建代理对象步骤

  1. 必须有接口,被代理对象要实现接口(代理通常是基于接口实现的)。
  2. 创建一个被代理对象的对象,该对象为业务对象
  3. 使用Proxy类提供的方法为被代理对象做一个代理对象并返回。

2.3 案例1

接口

package com.proxy;

public interface Skill {
    void jump();
    void sing();
}

对象

package com.proxy;

public class Star implements Skill{
    private String name;

    public Star(String name) {
        this.name = name;
    }

    public void jump(){
        System.out.println("跳舞");
    }
    public void sing(){
        System.out.println("唱歌");
    }
}

创建代理对象的工具类

package com.proxy;

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

public class StarAgentProxy {
    /*
    设计一个方法返回Star对象的代理对象
     */
    public static Skill getProxy(Star obj){
        //为Star对象生成一个代理对象
        return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("代理先做一些前操作,再让真正的对象进行方法");
                //method代表正在使用的方法,objects代表method方法的参数
                Object rs = method.invoke(obj,objects);
                System.out.println("做完方法的内容,之后的操作");
                //将对象的返回结果返回
                return rs;
            }
        });
    }
}

测试

package com.proxy;

public class Test {
    public static void main(String[] args) {
        //1、创建一个对象,对象的类必须实现接口
        Star s = new Star("明星");
        //为s创建一个代理对象
        Skill s2 = StarAgentProxy.getProxy(s);
        s2.jump();//走代理
        s2.sing();
    }
}

测试结果

代理先做一些前操作,再让真正的对象进行方法
跳舞
做完方法的内容,之后的操作
代理先做一些前操作,再让真正的对象进行方法
唱歌
做完方法的内容,之后的操作

从代码执行结果可以看出通过代理对象调用方法的执行流程是:
先走向代理,让代理做一些辅助工作,开发真正触发对象的方法的执行,回到代理中,由代理将方法的运行结果返回给方法的调用者

2.4 案例2

package com.tetsproxy;

public interface UserService {
    String login(String loginName,String passWord);
    void deleteUsers();
    String selectUsers();
}

package com.tetsproxy;

public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord) {
//        long startTime = System.currentTimeMillis();
        String rs = "登录名称密码错误";
        if("admin".equals(loginName)&&"111222".equals(passWord)){
            rs = "登录成功";
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        long endtTime = System.currentTimeMillis();
//        System.out.println("login方法耗时"+(endtTime - startTime) / 1000.0 + "s");
        return rs;
    }

    @Override
    public void deleteUsers() {
//        long startTime = System.currentTimeMillis();
        try {
            System.out.println("正在删除用户数据");
            Thread.sleep(2500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        long endtTime = System.currentTimeMillis();
//        System.out.println("deleteUsers方法耗时"+(endtTime - startTime) / 1000.0 + "s");
    }

    @Override
    public String selectUsers() {
//        long startTime = System.currentTimeMillis();
        String rs = "查询10000条数据";
        try {
            System.out.println("查询10000条数据");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        long endtTime = System.currentTimeMillis();
//        System.out.println("selectUsers方法耗时"+(endtTime - startTime) / 1000.0 + "s");
        return rs;
    }
}

package com.tetsproxy;

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

public class ProxyUtil {
    public static  UserService getProxy(UserService obj){
        return (UserService)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                long startTime = System.currentTimeMillis();
                Object rs = method.invoke(obj,objects);
                long endtTime = System.currentTimeMillis();
                System.out.println(method.getName()+"方法耗时"+(endtTime - startTime) / 1000.0 + "s");
                return rs;
            }
        });
    }
}

package com.tetsproxy;

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

public class TestTime {
    public static void main(String[] args) {
//        UserService u = new UserServiceImpl();
//        System.out.println(u.login("admin", "111222"));
//        System.out.println(u.selectUsers());
//        u.deleteUsers();
        //上面的代码实现会有很多重复代码

        UserService u = ProxyUtil.getProxy(new UserServiceImpl());
        System.out.println(u.login("admin", "111222"));
        System.out.println(u.selectUsers());
        u.deleteUsers();
    }
}

测试结果

login方法耗时1.015s
登录成功
查询10000条数据
selectUsers方法耗时3.012s
查询10000条数据
正在删除用户数据
deleteUsers方法耗时2.513s

如果想要实现任意接口都能用此代码进行代码可以将代码工具类的类型改为泛型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值