动态代理(附原理图)
代理:
代理主要体现在(代理类)和(委托类)之间的协调工作,
1.代理类 --proxy
承接着(委托类--目标类)的相关服务的(扩展处理--方法功能增强)的责任
分为 静态代理类 和 动态代理类。
*动态代理类:
利用java反射机制--Proxy类 和 InvocationHandler接口。
首先创造一个 (接口实现) 和一个 (InvocationHandler)实例,
{以类装载器、接口数组(Class对象),InvocationHandler来生成}--> (代理类)。
通过 代理类--Proxy 的代理,
(接口) 和 (实现类) 之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。
java.lang.reflect.Proxy只能代理(接口),不能代理类。
JDK提供的动态代理只适用于实现接口的类,
CGlib实现动态代理,它提供动态代理的对象可以不实现接口。
Java Proxy功能主要通过
java.lang.reflect.Proxy类 与
java.lang.reflect.InvocationHandler接口
实现。
*静态代理类:
在程序运行前,代理类的.class文件就已经存在。
2.委托类 --目标类
是接口的真正的实现者。
------------------------------------------------------------------------------------------------
动态代理 代码详解:
* 使用程序自动的去完成方法的增强,使用程序去生成代理类
* 获得代理类,Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
* 实现
Proxy.newProxyInstance(
ClassLoader,//确定代理类被加载到内存的类加载器,一般使用当前类的类加载器
Class[], //确定代理类需要实现的接口的字节码
InvocationHandler //接口,具体的处理类,在此我们使用到匿名内部类
//invoke(Object proxy,Method method,Object[] args) -->需要重写的方法
//* proxy,代理对象本身--代理
//* method,代理对象执行的方法 在内存的描述,即为一个反射对象
//* args,当前方法执行的具体、实际参数
//* invoke,委托类的每一个方法在执行时,将被invoke()拦截,即都会调用invoke()
)
**获得接口的两种方法:
final Subject realSubject = new RealSubject();
realSubject.getClass().getInterfaces();
new Class[]{Subject.class};
------------------------------------------------------------------------------------------------
代理作用:
对 (目标对象)--委托类 访问时,对其方法进行拦截,我们可以在此,对我们需要的方法进行功能增强。
即 拦截、增强
-------------------------------------------------------------------------------------------------
实例--用 代理 完成连接池
* 思路:
* 1.通过DriverManager获得链接(mysql)
* 2.使用自定义代理类获得链接
* 通过程序编写实现类(动态代理)
* 代理对象的每一个方法都会执行InvocationHandler的invoke方法
* 对具体的方法做出处理,通过方法的名称进行判断。method.getName()
* 注意:需要进行返回return --> 跳出方法
* 对被代理对象--委托类(具体Connection的实现类),进行其他方法的执行。
* 反射:method.invoke(被代理对象--委托类,实际参数)
* 3.目的,对需要增强的方法进行增强
* 将close方法原有的内容替换成,"将当前链接归还给连接池"。
*连接池 工具类 代码:
package cn.gp.pool.utils;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.Properties;
public class PoolProxyUtils {
//创建 连接池--集合,用来盛放 连接--Connection
private static LinkedList<Connection> pool = new LinkedList<Connection>();
//初始化 连接,将 连接 放入 连接池,并使用 动态代理
static {
try {
//获得 建立连接 的参数
InputStream is = PoolProxyUtils.class.getClassLoader()
.getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(is);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
//加载驱动
Class.forName(driver);
//建立连接池 **核心代码**
for (int x = 0; x < 10; x++) {
// 获得 连接对象--委托类
final Connection conn = DriverManager.getConnection(url, user,
password);
//创建 代理对象
Connection connctionProxy = (Connection) Proxy.newProxyInstance(
PoolProxyUtils.class.getClassLoader(), // 提供 类加载器
new Class[] { Connection.class }, // 提供 委托类接口
new InvocationHandler() { // 具体 处理类
@Override
public Object invoke(Object proxy,
Method method, Object[] args)
throws Throwable {
// 查看正在使用 委托类的哪个方法
String name = method.getName();
// 增强close方法
if ("close".equals(name)) {
// 将 连接 归还 连接池
pool.add((Connection) proxy);
// 跳出invoke()
return null;
}
// 其他方法 调用 原类 的方法
return method.invoke(conn, args);
}
});
// 将 代理类对象 添加到 连接池 中
pool.add(connctionProxy);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
//获得连接
public static Connection getConnection() {
//如果 连接池 中有 连接,就获取
if (pool.size() > 0) {
return pool.get(0);
}
//连接池中没有 连接,稍等,递归,调用自身
try {
Thread.sleep(500);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
return getConnection();
}
//释放资源
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null) {
st.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}}}}}
-----------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
**调用原理: