一,装饰者设计模式
- 1,定义装饰类(增强类)实现和被装饰类(被增强类)相同的接口
- 2,在装饰类中声明被装饰类的引用
- 3,在装饰类的方法中,使用被装饰调用原方法
package t1.example.util;
import t1.example.dao.UserDao;
public class UserDaoWrapper implements UserDao {
private UserDao userDao;
public UserDaoWrapper(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
System.out.println("权限校验");
this.userDao .addUser();
System.out.println("日志记录");
}
@Override
public void deleteUser() {
userDao.deleteUser();
}
@Override
public void updateUser() {
userDao.updateUser();
}
@Override
public void SelectUser() {
userDao.SelectUser();
}
}
- 作用
- 在不侵入被装饰类源码的前提下,增强某个功能!
- 特点
- 不能控制被装饰类对象
- 缺点
- 需要重写接口中的所有方法,破坏了单一职责原则
二,Proxy动态代理
基于接口的方法增强
方式一:定义类实现InvocationHandler接口增强addUser方法
package t1.example.demo;
import t1.example.dao.UserDao;
import t1.example.dao.UserDaoImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理模式
* 增强方法
* Proxy类中的newProxyInstance方法
*/
public class Demo03 {
public static void main(String[] args) {
//ClassLosder loader:被代理类对应的类加载器
//Class<?>[] interfacers:被代理类所实现的接口
//InvocationHandler h:一个用以增强代理类的处理器
UserDao userDao = new UserDaoImpl();
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
new MyInvocationHandler(userDao));
userDaoProxy.addUser();
userDaoProxy.SelectUser();
}
}
/**
* 相当于代理类增强器,用以增强代理类
*/
class MyInvocationHandler implements InvocationHandler{
//声明一个被代理类的引用
private UserDao userDao;
public MyInvocationHandler(UserDao userDao) {
this.userDao = userDao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Method method:被代理类的原方法
//Object[] args:被代理类方法的实际参数
String methodName = method.getName();
Object returnValue = null;
if("addUser".equals(methodName)){
//只有addUser需要增强
System.out.println("权限校验");
returnValue = method.invoke(userDao, args);
System.out.println("日志记录");
}else{
//其他方法不增强
method.invoke(userDao, args);
}
return returnValue;
}
}
方式二:使用InvocationHandler接口的匿名内部类对象
package t1.example.demo;
import t1.example.dao.UserDao;
import t1.example.dao.UserDaoImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Demo04 {
/**
* 动态代理模式
*/
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Object returnValue = null;
if("addUser".equals(methodName)){
//只有addUser需要增强
System.out.println("权限校验");
returnValue = method.invoke(userDao, args);
System.out.println("日志记录");
}else{
//其他方法不增强
method.invoke(userDao, args);
}
return returnValue;
}
});
userDaoProxy.addUser();
userDaoProxy.SelectUser();
}
}
优点:不需要重写接口所有的方法!
三,连接池概念
在不使用连接池的情况下, 如果有100个用户要操作数据库,对应要创建100个连接对象,操作数据库完毕,还需要销毁100个连接对象,创建连接和销毁连接是非常浪费系统性能!
如果使用连接池,连接的创建,只在连接池初始化时才进行,当用户要操作数据库时,只需要从连接池中取出已经创建好的连接对象即可,操作数据库完毕,不需要销毁连接,只需将连接对象归还到连接池
总结
连接池提高了操作数据库的性能!
四,自定义连接池基础版
- 初始化时,创建一些连接对象,并存储到LinkedList(增删快查询慢)集合中
- 从连接池中取出连接
- 把连接归还连接池
package t1.example.util;
//自定义连接池
import java.sql.Connection;
import java.util.LinkedList;
public class MyDataSourse {
int initPoolSize = 3;
LinkedList<Connection> connections = new LinkedList<>();
//当连接池初始化时,创建一些连接,并存储起来
public MyDataSourse() {
creatConnections();
}
public void creatConnections(){
for (int i = 0;i<initPoolSize;i++){
try {
Connection connection = JDBCUtils.getConnection();
connections.add(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Connection getConnection(){
if(connections.size()==0||connections.isEmpty()){
creatConnections();
}
Connection connection = connections.remove(0);
return connection;
}
public void addBack(Connection connection){
connections.add(connection);
}
}
存在的问题
- 自己定义了归还连接的方法addBack。维护困难
五,自定义连接池优化版
解决问题思路
一般开发都能记住Connection类中close方法
将该close方法功能改变为归还连接
中间类ConnectionWrapper,专注于非close方法的调用
package t1.example.util;
/*
public : 任何地方都能访问
protected : 只在子父类关系中
默认 : 同包
private : 本类
*/
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* 中间类
* 处理其他方法
* 使用普通Connection调用一次
*/
public class ConnectionWrapper implements Connection {
//protected:只能在子父类进行访问
protected Connection connection;
public ConnectionWrapper() {
}
public ConnectionWrapper(Connection connection) {
this.connection = connection;
}
@Override
public Statement createStatement() throws SQLException {
return connection.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}
//...
}
package t1.example.util;
import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class MyConnectionWrapper extends ConnectionWrapper {
//声明被代理类引用
private List<Connection> connectionList;
public MyConnectionWrapper(Connection connection, List<Connection> connectionList) {
super(connection);
this.connectionList = connectionList;
}
@Override
public void close() throws SQLException {
//增强closa:归还连接
//把Connection归还给连接池
connectionList.add(connection);
}
}
存在的问题:必须要重写接口中的所有方法
六,自定义连接池的终极版
package t1.example.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.LinkedList;
/**
* 自定义连接池终极版
*/
public class MyDataSource {
int initPoolSize = 3;
LinkedList<Connection> connections = new LinkedList<>();
public MyDataSource(){
createConnections();
}
public void createConnections(){
for (int i = 1 ; i <= initPoolSize ; i++) {
try {
Connection connection = JDBCUtils.getConnection();
connections.add(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 取出连接
* @return
*/
public Connection getConnection(){
//连接池中的连接够用
if (connections.size() == 0 || connections.isEmpty()) {
//连接池中的连接不够用 , 新建一些连接存储连接池中
createConnections();
}
Connection connection = connections.remove(0);//普通连接对象
//根据普通连接对象 获取 一个连接代理对象(增强连接对象)
Connection connectionProxy = (Connection) Proxy.newProxyInstance(
connection.getClass().getClassLoader(),
connection.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//处理增强close方法
String methodName = method.getName();
Object returnValue = null;
if ("close".equals(methodName)) {
//如果是close方法,归还连接
returnValue = connections.add(connection);
} else {
//如果不是close方法,就执行原有功能
returnValue = method.invoke(connection, args);
}
return returnValue;
}
});
return connectionProxy;
}
/**
* 归还连接
* @param connection
*/
// public void addBack(Connection connection){
// connections.add(connection);
// }
}
使用动态代理方式解决装饰者设计模式中的弊端:必须要重写接口中的所有方法
7,Java内置注解
概念:就是一个修饰符
特点: 是JDK5.0之后引入的特性。以“@注解名”形式存在
作用:
跟踪代码依赖性
执行编译时格式检查
代替已有的配置文件
@Overirde:标记指定方法是一个重写方法,否则报错
@Deprecated:标记一个类、字段、方法是一个过时的!
@SuppressWarings:压制警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
value : 注解所压制的警告的类型
unchecked 未检查的转化,如集合没有指定类型还添加元素
unused 未使用的变量
resource 有泛型未指定类型
path 在类路径,原文件路径中有不存在的路径
deprecation 使用了某些不赞成使用的类和方法
fallthrough switch语句执行到底没有break关键字
rawtypes 没有写泛型,比如: List list = new ArrayList();
all 全部类型的警告(用的最多的)
8,注解分类
标记注解
注解中没有属性
比如:@Override、@Deprecated
单值注解
注解中只有一个属性(属性为value时可以不写value)
比如:@SuppressWarings
完整注解
注解中有多个属性
10,自定义注解
格式:
public @interface 注解名 {
数据类型 属性名1() default 默认值1;
数据类型 属性名2() ;
//没有默认值,在使用时必须要给属性赋值,有默认值依然可以重新赋值
//通过案例可知只有单独使用value命名的属性时可以省略
}
11,元注解概述
概述:作用在自定义注解上,规定自定义注解的作用区域、存活策略(生命周期)!
常用的元注解:
@Target:规定自定义注解的作用区域
TYPE:类、接口、注解、枚举
FIELD:成员你变量
METHOD:成员方法
PARAMETER:形参
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
PACKAGE:包
@Retention:规定自定义注解的存活策略
SOURCE : 仅存活在源码
CLASS : 存活在编译期
RUNTIME : 存活在运行时