数据库连接池
池化思想
优点:
1.减少创建和销毁的资源开销,提高效率
2.控制服务器的内存开销,使程序更加稳定
数据库连接池背景
- 数据库连接是一种关键的、有限的、昂贵的资源,这点在多用户的网页应用程序中体现得尤为突出
- 对数据库连接的管理能显著影响到整个程序的
性能指标
,数据库连接池正是针对这个问题提出的
数据库连接池功能
数据库连接池负责分配、管理、释放数据库连接
,它允许应用程序重复使用
一个现有的数据库连接,而不是再重新建立一个,这项技术明显提高了数据库的性能
自定义数据库连接池
DataSource
DataSource接口
- javax.sql.DataSource接口:数据源(数据库连接池)| Java官方提供的数据库连接池规范接口
- 如果想实现数据库连接池技术,就必须实现
DataSource
接口 - 核心能力:获取数据库连接对象:
Connection getConnection()
;
实现代码展示
//1、实现DataSource接口(遵循规范)
public class MyDataSource implements DataSource {
//2、定义一个容器, 存储连接对象(容器功能)
private List<Connection> conns = new ArrayList<>();
public MyDataSource(){
//创建一些初始的连接对象,存入容器中;初始连接数为3
for (int i = 0; i < 3; i++) {
Connection conn = JDBCUtils.getConnection();
conns.add(conn);
}
System.out.println(conns);
}
//3、获取连接对象的功能
@Override
public Connection getConnection() throws SQLException {
//获取连接对象,并从容器中将其移除
Connection conn = conns.remove(0);
return conn;
}
//4、归还连接对象的功能
public void back(Connection conn){
conns.add(conn);
System.out.println(conns);
}
....
}
存在问题
解决方式
如何对一个对象的功能进行增强/改造(归还连接)
1、继承(太局限了,一般无法使用)
需要增强的那个对象必须是我们自己new出来的;必须知道对象的创建细节。
2、装饰者设计模式
可以在不知道增强对象源代码的时候,实现对象的功能增强/扩展;相对于继承来讲,更加灵活
缺点:如果接口/父类中抽象方法过多,实现/继承后,对于所有抽象方法都需要做实现,编码很麻烦。解决方案就是 -- 适配器设计模式。
① 装饰者类和被装饰者对象的类实现相同的接口/继承相同的父类
public class MyConn implements Connetion{
}
② 装饰者类中要有一个引用接收被装饰者对象(需要用被装饰者对象完成功能)
public class MyConn implements Connetion{
private Connection conn;
public MyConn(Connection conn){
this.conn = conn;
}
}
③ 将其他方法按照被装饰者对象的方式做实现,改造需要增强的方法
public class MyConn implements Connetion{
private Connection conn;
public MyConn(Connection conn){
this.conn = conn;
}
public void close(){
//conn.close();
//将conn添加回容器
}
}
3、代理
3.1、静态代理设计模式
可以在不知道增强对象源代码的时候,实现对象的功能增强;只能增强原本声明的方法;不能额外增加方法。(和装饰者的区别)
缺点:如果接口/父类中抽象方法过多,实现/继承后,对于所有抽象方法都需要做实现,编码很麻烦。解决方案就是 -- 适配器设计模式。
① 代理类和被代理对象的类实现相同的接口/继承相同的父类
② 代理类中要有一个引用接收被代理对象(需要用被代理对象完成功能)
③ 将其他方法按照被代理对象的方式做实现,改造需要增强的方法
3.2、动态代理技术
创建对象不需要依赖于磁盘中的class文件,在运行的过程中,动态生成字节码对象,并且基于这个字节码对象构建代理对象。
解决:① 简化复写抽象方法的麻烦 ② 防止类爆炸问题(项目中的类文件不允许超过65535个)
装饰者设计模式
动态代理技术
动态代理
动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心
在改变代理对象的方法的情况下对方法进行增强
组成:被代理对象 --真实的对象 | 代理对象 -- 内存中的对象(字节码对象)
要求:代理对象和被代理对象都要实现同一个接口
实现方法:Proxy.newProxyInstance()
newProxyInstance
方法详解
Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h)
参数 | 说明 |
---|---|
ClassLoader loader | 定义了由哪个classloader对象对生成的代理类进行加载 |
Class<?>[]interfaces | 表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法 |
InvocationHandler h | 一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用 |
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法
invoke
方法详解
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
参数 | 说明 |
---|---|
Object proxy | 代理类代理的真实代理对象com.sun.proxy.$Proxy0 |
Method method | 所要调用某个对象真实的方法的method对象 |
Object[] args | 代理对象方法的传递参数 |
网友评论