Java——动态代理

一、程序为什么需要代理?代理长什么样?

1.1、对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。

1.2、对象有什么方法想被代理,代理就一定要有对应的方法

1.3、中介如何知道要派有唱歌、跳舞方法的代理呢?-->接口

1.4、示例

二、如何为 Java 对象创建一个代理对象?

java.lang.reflect.Proxy 类:提供了为对象产生代理对象的方法:

1.4示例的代码

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

/**
 * 代理工具类:中介公司,专门负责创建代理对象并返回给别人使用
 */
public class ProxyUtil {
    // 创建一个明星对象的代理对象返回。
    public static StarService createProxy(Star s){
        /**
         * 参数一:用于执行用哪个类加载器去加载生成的代理类。
         * 参数二:用于指定代理类需要实现的接口: 明星类实现了哪些接口,代理类就实现哪些接口
         * 参数三:用于指定代理类需要如何去代理(代理要做的事情)。
         */
        StarService proxy = (StarService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                s.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 用来声明代理对象要干的事情。
                        // 参数一: proxy接收到代理对象本身(暂时用处不大)
                        // 参数二: method代表正在被代理的方法
                        // 参数三: args代表正在被代理的方法的参数
                        String methodName = method.getName();
                        if("sing".equals(methodName)){
                            System.out.println("准备话筒,收钱20万!");
                        }else if("dance".equals(methodName)){
                            System.out.println("准备场地,收钱100万!");
                        }
                        // 真正干活(把真正的明星对象叫过来正式干活)
                        // 找真正的明星对象来执行被代理的行为:method方法
                        Object result = method.invoke(s, args);
                        return result;
                    }
                });
        return proxy;
    }
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Star implements StarService{
    private String name;

    @Override
    public void sing(String name) {
        System.out.println(this.name + "表演唱歌:" + name);
    }

    @Override
    public String dance() {
        System.out.println(this.name + "表演跳舞:魅力四射!" );
        return "谢谢!谢谢!";
    }
}
// 明星行为接口
public interface StarService {
    void sing(String name);
    String dance();
}
public class Test {
    public static void main(String[] args) {
        // 目标:创建代理对象。
        // 1、准备一个明星对象:设计明星类。
        Star star = new Star("章若楠");
        // 2、为章若楠创建一个专属与她的代理对象。
        StarService proxy = ProxyUtil.createProxy(star);
        proxy.sing("《红昭愿》");
        System.out.println(proxy.dance());
    }
}

三、解决实际问题、掌握使用代理的好处

场景

某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。

代码

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

public class ProxyUtil {
    public static <T> T createProxy(T obj) {
        T proxy = (T) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                obj.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long start = System.currentTimeMillis(); // 记录开始时间 1970年1月1日0时0分0秒 走到此刻的总毫秒值
                        // 真正调用业务对象被代理的方法
                        Object result = method.invoke(obj, args);

                        long end = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:"+(end-start)/1000.0+"秒");
                        return result;
                    }
                });
        return proxy;
    }
}
/**
 *  用户业务接口
 */
public interface UserService {
    // 登录功能
    void login(String loginName,String passWord) throws Exception;
    // 删除用户
    void deleteUsers() throws Exception;
    // 查询用户,返回数组的形式。
    String[] selectUsers() throws Exception;
    String[] selectUsers2() throws Exception;
}
/**
 * 用户业务实现类(面向接口编程)
 */
public class UserServiceImpl implements UserService{
    @Override
    public void login(String loginName, String passWord) throws Exception {
        // ----------------------
        if("admin".equals(loginName) && "123456".equals(passWord)){
            System.out.println("您登录成功,欢迎光临本系统~");
        }else {
            System.out.println("您登录失败,用户名或密码错误~");
        }
        Thread.sleep(1000);
        // --------------------------
    }

    @Override
    public void deleteUsers() throws Exception{
        System.out.println("成功删除了1万个用户~");
        Thread.sleep(1500);
    }

    @Override
    public String[] selectUsers() throws Exception{
        System.out.println("查询出了3个用户");
        String[] names = {"张全蛋", "李二狗", "牛爱花"};
        Thread.sleep(500);

        return names;
    }

    @Override
    public String[] selectUsers2() throws Exception {
        System.out.println("查询出了3000个用户");
        String[] names = {"张全蛋2", "李二狗2", "牛爱花2"};
        Thread.sleep(2500);

        return names;
    }
}
import java.util.Arrays;

/**
 * 目标:使用动态代理解决实际问题,并掌握使用代理的好处。
 */
public class Test {
    public static void main(String[] args) throws Exception{
        // 1、创建用户业务对象。
        UserService userService = ProxyUtil.createProxy(new UserServiceImpl());

        // 2、调用用户业务的功能。
        userService.login("admin", "123456");

        userService.deleteUsers();

        String[] names = userService.selectUsers();
        System.out.println("查询到的用户是:" + Arrays.toString(names));

        String[] names2 = userService.selectUsers2();
        System.out.println("查询到的用户是:" + Arrays.toString(names2));
    }
}

注意:此案例的代理思想,其实也是AOP(切面思想)。即在不修改业务逻辑代码的情况下,通过代理实现横切关注点(如日志、性能统计等)的模块化。

四、体会Spring思想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值