Javase-动态代理

动态代理

1. 动态代理介绍,准备功能

1.1 动态代理介绍

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

通俗的讲,动态代理就相当于经济人的地位,当老板需要具有唱歌跳舞能力的明星时,由经纪人与明星联系,而不是由明星直接与老板对接.

1.2 准备功能

定义接口,并实现接口

public interface Star {
    String sing(String name);
    void dance();
}
public class BigStar implements Star{
    private String name;

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

    @Override
    public String sing(String name) {
        System.out.println(this.name+"正在唱"+name);
        return "谢谢";
    }

    @Override
    public void dance() {
        System.out.println(this.name+"正在跳舞");
    }
}

2.生成动态代理对象

2.1 Proxy工具类

写一个为BigStar生成动态代理对象的工具类。这里需要用Java为开发者提供的一个生成代理对象的类叫Proxy类。
通过Proxy类的newInstance(…)方法可以为实现了同一接口的类生成代理对象。 调用方法时需要传递三个参数,该方法的参数解释可以查阅API文档,如下:
loader -定义代理类的类加载器
interfaces -代理类要实现的接口列表
h -指派方法调用的调用处理程序

public class ProxyUtil {
    public static Star creatProxy(Object o){
         /* newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
                参数1:用于指定一个类加载器//是代理对象与目标对象使用的同一种类加载器
                参数2:指定生成的代理长什么样子,也就是有哪些方法//得到与目标对象相同的接口对象
                参数3:用来指定生成的代理对象要干什么事情
                */
        // Star starProxy = ProxyUtil.createProxy(s);
        // starProxy.sing("好日子") starProxy.dance()
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class}, new InvocationHandler() {
                    @Override
                    //此方法在代理对象调用任何方法时都会执行
                    //参数1:代理对象本身的引用.一般不用
                    //参数2:代理对象调用的那个方法.
                    //参数3:是参数2的参数.
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       if(method.getName().equals("sing")){
                           System.out.println("准备话筒,收钱20w");
                       }else if(method.getName().equals("dance")){
                           System.out.println("准备场地,收钱200w");
                       }
                       //告知虚拟机执行此方法
                        return method.invoke(o,args);//是真实对象方法的返回值;没有返回值就返回null
                    }
                });
        return starProxy;
    }
}

2.2 生成代理对象

调用写好的ProxyUtil工具类,为BigStar对象生成代理对象

public class Test {
    public static void main(String[] args) {
        BigStar s = new BigStar("杨超越");
        Star starProxy = ProxyUtil.creatProxy(s);

        String rs = starProxy.sing("好日子");
        System.out.println(rs);
        starProxy.dance();
    }
}

运行结果如下:
准备话筒,收钱20w
杨超越正在唱好日子
谢谢
准备场地,收钱200w
杨超越正在跳舞

3.动态代理应用

3.1 定义用户业务接口

/**
 *  用户业务接口
 */
public interface UserService {
    // 登录功能
    void login(String loginName,String passWord) throws Exception;
    // 删除用户
    void deleteUsers() throws Exception;
    // 查询用户,返回数组的形式。
    String[] selectUsers() throws Exception;
}

3.2 实现接口

/**
 * 用户业务实现类(面向接口编程)
 */
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;
    }
}

3.3 生成动态代理对象(前置增强与后置增强)

当用户实现业务中有大量重复代码时,可以将其抽取出来放在动态代理对象当中
前置增强: 在方法调用前执行一次
后置增强: 在方法调用结束后执行一次

public class ProxyUtil {
    public static Object creatProxy(Class clazz) {

        Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      //前置增强
                        long startTime = System.currentTimeMillis();
                        Object result = method.invoke(clazz.newInstance(), args);
                      //后置增强
                        long endTime = System.currentTimeMillis();
                        System.out.println("login方法执行耗时:" + (endTime - startTime) / 1000.0 + "s");
                        return result;
                    }
                });
        return obj;
    }
}

3.4 测试类

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


        // 2、调用用户业务的功能。

        userService.login("admin", "123456");
        System.out.println("----------------------------------------------------");

        userService.deleteUsers();
        System.out.println("----------------------------------------------------");

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

    }
}

测试结果:
您登录成功,欢迎光临本系统~
login方法执行耗时:1.029s
成功删除了1万个用户~
login方法执行耗时:1.501s
查询出了3个用户
login方法执行耗时:0.506s
查询到的用户是:[张三,李四,王五]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值