JDK动态代理

 

1 什么是JDK动态代理

刚刚写ItcastConnection时爽么?因为Connection中的方法太多了,每个都要写,所以很累吧。累点到是没什么,可以完成功能就是好的。但是不是什么时候可以用代理的,有时你可能会遇到要代理的东西,只有在运行时才能知道,所以你不可能先把代理写出来!这时就需要使用动态代理。

JDK动态代理是JavaSE中一个高级特性,不是那么好理解的,但是它可是框架们的"秘密武器"。你要是可以理解它,那么将来在学习框架时,你就会知道框架是怎么完成一些"神奇功能"的。

 

动态代理的作用:在运行时生成一个实现了指定接口的对象。

  例如在运行时生成一个对象,这个对象实现了Connection接口。

 

2 JDK动态代理之Hello World

我们要写一个程序,这个程序会在运行时动态的生成一个对象,这个对象会实现Connection接口。

Connectoin c = (Connection)Proxy.newInstance(Connetion.class);

上面代码只是示意代码,不能编译通过的。

上面代码有个问题:生成一个实现了指定接口的对象,但是我们知道实现接口,需要为接口中每个方法添加实现内容,那么这个动态代理对象它是怎么实现Connection接口中的方法的呢?也就是说,我现在如果调用了代理对象的close()方法,它会执行什么呢?这就是问题!

想生成代理对象,还需要提供实现内容!

别的先别去管,先来看一个接口:InvocationHandler。

class HelloWorldHandler implements InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)

            throws Throwable {

        System.out.println("Hello 动态代理!");

        return
null;

    }

}

 

InvoactionHandler接口只有一个方法,invoke()!方法的参数你不要去管是什么意思,只需要知道它只有一个方法,名字叫invoke(),一会儿再去讨论它参数的含义。

  Connectoin c = (Connection)Proxy.newInstance(Connetion.class, new HelloWorldHandler());

  上面代码还是示意代码,不能编译通过。

我们这回在创建代理对象时,多给出了一个参数,是一个接口的实现类。实现类中有一条输出语句"Hello 动态代理!",现在生成的代理对象是Connection接口的实现类对象,你调用代理对象的任何方法都会调用HelloWorldHandler的invoke()方法,即输出"Hello 动态代理!"。

Connectoin c = (Connection)Proxy.newInstance(Connetion.class, new HelloWorldHandler());

c.close();

c.toString();

c.createStatement();

还是示意代码!

上面示意代码中调用了三个方法,无论哪个方法都会输出"Hello 动态代理!"。现在你知道InvocationHandler接口的作用了吧。

    public
void fun2() throws SQLException {

        ClassLoader loader = Thread.currentThread().getContextClassLoader();

        Class[] interfaces = {Connection.class};

        InvocationHandler h = new HelloWorldHandler();

        Connection con = (Connection)Proxy.newProxyInstance(loader, interfaces, h);

        con.close();

        con.toString();

        con.createStatement();

    }

 

3 真正的代理

虽然我们学会了动态代理,但还没有真正的代理。真正的代理是需要一个真正的连接对象,然后我们的代理对象使用它来完成任务。为了说明这个真正的代理,需要写几个类:

public
interface Waiter {

    public
void serve();

}

public
class WaiterImpl implements Waiter {

    public
void serve() {

        System.out.println("服务...");

    }

}

 

上面代码中写了一个Waiter接口,和一个WaiterImpl,它是Waiter接口的实现类。现在我们要写一个WaiterImpl的代理类。

public
class WaiterProxy implements Waiter {

    private Waiter waiter;

    public WaiterProxy(Waiter waiter) {

        this.waiter = waiter;

    }

    public
void serve() {

        waiter.serve();

    }

}

 

上面代理中,WaiterProxy就是一个代理类,当然,这个代理类没有实际的意义,因为它没有做任何的改变,所以没有意思!通常代理类是这样的,它会去实现一个接口,但它还需要一个该接口的实现类对象,然后所有实现都使用这个对象来完成。象是上面的代理中,WaiterProxy是一个代理类,它实现了Waiter接口,而且它还需要一个Waiter类型的对象,然后所有的实现都是代理这个对象功能。但是通常代理类会对被代理的对象的一些行为做一些改动,我们的例子中没有做。

 

上面的WaiterProxy虽然是一个代理类,但它不是动态代理。下面是通过JDK动态代理来生成一个代理对象。

public
class WaiterHandler implements InvocationHandler {

    private Waiter waiter;

    public WaiterHandler(Waiter waiter) {

        this.waiter = waiter;

    }

    public Object invoke(Object proxy, Method method, Object[] args)

            throws Throwable {

        return method.invoke(waiter, args);

    }

}

 

        ClassLoader loader = Thread.currentThread().getContextClassLoader();

        Class[] interfaces = {Waiter.class};

        Waiter watier = new WaiterImpl();

        InvocationHandler h = new WaiterHandler(watier);

        Waiter proxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h);

        proxy.serve();

 

4 使用动态代理完成连接池

public
class ItcastDataSource implements DataSource {

    private String username;

    private String password;

    private String url;

    private String driverClassName;

    

    private List<Connection> list = new ArrayList<Connection>();

    private
boolean
flag = true;

 

    private
void init() throws SQLException {

        flag = false;

        try {

            Class.forName(driverClassName);

        } catch(ClassNotFoundException e) {

            throw
new RuntimeException(e);

        }

        for(int i = 0; i < 5; i++) {

            final Connection con = DriverManager.getConnection(url, username, password);

            ClassLoader l = Thread.currentThread().getContextClassLoader();

            Class[] ins = {Connection.class};

            InvocationHandler h = new InvocationHandler() {

                public Object invoke(Object proxy, Method method, Object[] args)

                        throws Throwable {

                    if(method.getName().equals("close")) {

                        list.add((Connection)proxy);

                        return
null;

                    } else {

                        return method.invoke(con, args);

                    }

                }

            };

            Connection proxy = (Connection)Proxy.newProxyInstance(l, ins, h);

            list.add(proxy);

        }

    }

    

    public Connection getConnection() throws SQLException {

        if(flag) {

            init();

        }

        if(list.size() > 0) {

            return
list.remove(0);

        }

        throw
new RuntimeException();

    }

......

}

 

JDK动态代理连接池的更多相关文章

  1. Spring AOP详解 、 JDK动态代理、CGLib动态代理

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

  2. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  3. 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理

    [原创]分布式之缓存击穿   什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查 ...

  4. Spring AOP JDK动态代理与CGLib动态代理区别

    静态代理与动态代理 静态代理 代理模式 (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. (2)静态代理由 业务实现类.业务代理类 两部分 ...

  5. JDK动态代理与CGLib动态代理

    1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...

  6. JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析

    通过前面几篇的分析,我们知道代理类是通过Proxy类的ProxyClassFactory工厂生成的,这个工厂类会去调用ProxyGenerator类的generateProxyClass()方法来生成 ...

  7. 017 Java中的静态代理、JDK动态代理、cglib动态代理

    一.静态代理 代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. 静态代理由业务实现类.业务代理类两部分组成.业务实现类负责实现主要的业务方法,业 ...

  8. JDK动态代理深入理解分析并手写简易JDK动态代理(下)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...

  9. JDK动态代理深入理解分析并手写简易JDK动态代理(上)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...

随机推荐

  1. [Tools] Create a Simple CLI Tool in Node.js with CAC

    Command-line tools can help you with all sorts of tasks. This lesson covers the very basics of setti ...

  2. JAVA Eclipse 启动 Eclipse 弹出“Failed to load the JNI shared library jvm_dll”怎么办

    原因1:给定目录下jvm.dll不存在. 对策:(1)重新安装jre或者jdk并配置好环境变量.(2)copy一个jvm.dll放在该目录下. 原因2:eclipse的版本与jre或者jdk版本不一致 ...

  3. How to Handle Exception

  4. oracle 序列重置

    问题一:怎样重置oracle序列 oracle序列创建以后,假设想重置序列从 0 開始,逐渐递增1,能够採用例如以下存储过程: create or replace procedure reset_se ...

  5. Guice 学习(七)常量和属性的注入( Constant and Property Inject)

    1.常量注入方式 package com.guice.ConstantInjectDemo; import com.google.inject.Binder; import com.google.in ...

  6. MySQL加入服务、设置password、改动password

    修正:加入MySQL服务时,能够不带版本.也就说以下的全部MySQL57能够直接写成MySQL!希望大家注意. MySQL安装好之后,往往还须要再做一些设置! 1.加入MySQL服务: 输入命令cmd ...

  7. git revert 后悔了 还原修改前的版本 + git 常用命令

    昨天手残 然后在GitHub for windows 上点了revert 然后就给重置了 更手残的是又给同步了 .  但是 GitHub 会保留之前的版本 . 只要删掉本次修改就可. 解决方案:  g ...

  8. IOS 10 微信 ajax readystate=0 status=0 解决方法

    最近做了一个 基于微信访问的网页系统 发现IOS10.2.1 版本 访问的时候 AJAX报错,安卓和IOS11.4.1 没有这样的问题. 通过Fiddler抓包发现,AJAX请求时 报错信息为  {& ...

  9. jquery的find()

    jQuery 遍历 - find() 方法 jQuery 遍历参考手册 实例 搜索所有段落中的后代 span 元素,并将其颜色设置为红色: $("p").find("sp ...

  10. 实现Nullable 可空类型

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace demo ...