From be1213dc383210ca0b181f19529fbbf220e7cd8f Mon Sep 17 00:00:00 2001
From: FuriousPws002 <1938485828@qq.com>
Date: Fri, 19 Apr 2024 22:54:55 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 1 +
.../statement/PrepareStatementHandler.java | 5 +++
.../executor/statement/StatementHandler.java | 4 ++
.../org/apache/ibatis/plugin/Interceptor.java | 17 +++++++
.../ibatis/plugin/InterceptorChain.java | 30 +++++++++++++
.../java/org/apache/ibatis/plugin/Plugin.java | 44 +++++++++++++++++++
.../apache/ibatis/session/Configuration.java | 18 +++++++-
.../apache/ibatis/plugin/PageInterceptor.java | 28 ++++++++++++
.../apache/ibatis/session/SqlSessionTest.java | 18 ++++++++
9 files changed, 164 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/org/apache/ibatis/plugin/Interceptor.java
create mode 100644 src/main/java/org/apache/ibatis/plugin/InterceptorChain.java
create mode 100644 src/main/java/org/apache/ibatis/plugin/Plugin.java
create mode 100644 src/test/java/org/apache/ibatis/plugin/PageInterceptor.java
diff --git a/README.md b/README.md
index 0912090..41222a8 100644
--- a/README.md
+++ b/README.md
@@ -8,3 +8,4 @@
[5.resultType结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/5.resultType%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
[6.resultMap结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/6.resultMap%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
[7.动态sql](https://github.com/FuriousPws002/mini-mybatis/wiki/7.%E5%8A%A8%E6%80%81sql "Markdown")
+[8.插件支持](https://github.com/FuriousPws002/mini-mybatis/wiki/8.%E6%8F%92%E4%BB%B6%E6%94%AF%E6%8C%81 "Markdown")
diff --git a/src/main/java/org/apache/ibatis/executor/statement/PrepareStatementHandler.java b/src/main/java/org/apache/ibatis/executor/statement/PrepareStatementHandler.java
index 129b1aa..6e6f88f 100644
--- a/src/main/java/org/apache/ibatis/executor/statement/PrepareStatementHandler.java
+++ b/src/main/java/org/apache/ibatis/executor/statement/PrepareStatementHandler.java
@@ -61,4 +61,9 @@ public List query(Statement statement) throws SQLException {
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
+
+ @Override
+ public BoundSql getBoundSql() {
+ return boundSql;
+ }
}
diff --git a/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java b/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
index f50fefb..5de9a1e 100644
--- a/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
+++ b/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
@@ -5,6 +5,8 @@
import java.sql.Statement;
import java.util.List;
+import org.apache.ibatis.mapping.BoundSql;
+
/**
* @author furious 2024/4/8
*/
@@ -17,4 +19,6 @@ public interface StatementHandler {
void parameterize(Statement statement) throws SQLException;
List query(Statement statement) throws SQLException;
+
+ BoundSql getBoundSql();
}
diff --git a/src/main/java/org/apache/ibatis/plugin/Interceptor.java b/src/main/java/org/apache/ibatis/plugin/Interceptor.java
new file mode 100644
index 0000000..1316d5c
--- /dev/null
+++ b/src/main/java/org/apache/ibatis/plugin/Interceptor.java
@@ -0,0 +1,17 @@
+package org.apache.ibatis.plugin;
+
+import org.apache.ibatis.session.Configuration;
+
+/**
+ * @author furious 2024/4/19
+ */
+public interface Interceptor {
+
+ String pointcut();
+
+ Object intercept(Invocation invocation) throws Throwable;
+
+ default Object plugin(Object target, Configuration configuration) {
+ return Plugin.wrap(target, configuration, this);
+ }
+}
diff --git a/src/main/java/org/apache/ibatis/plugin/InterceptorChain.java b/src/main/java/org/apache/ibatis/plugin/InterceptorChain.java
new file mode 100644
index 0000000..7a9eea8
--- /dev/null
+++ b/src/main/java/org/apache/ibatis/plugin/InterceptorChain.java
@@ -0,0 +1,30 @@
+package org.apache.ibatis.plugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ibatis.session.Configuration;
+
+/**
+ * @author furious 2024/4/19
+ */
+public class InterceptorChain {
+
+ private final Configuration configuration;
+ private final List interceptors = new ArrayList<>();
+
+ public InterceptorChain(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ public T pluginAll(Object target) {
+ for (Interceptor interceptor : interceptors) {
+ target = interceptor.plugin(target, configuration);
+ }
+ return (T) target;
+ }
+
+ public void addInterceptor(Interceptor interceptor) {
+ interceptors.add(interceptor);
+ }
+}
diff --git a/src/main/java/org/apache/ibatis/plugin/Plugin.java b/src/main/java/org/apache/ibatis/plugin/Plugin.java
new file mode 100644
index 0000000..cf2eeb2
--- /dev/null
+++ b/src/main/java/org/apache/ibatis/plugin/Plugin.java
@@ -0,0 +1,44 @@
+package org.apache.ibatis.plugin;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Objects;
+
+import org.apache.ibatis.session.Configuration;
+
+/**
+ * @author furious 2024/4/19
+ */
+public class Plugin implements InvocationHandler {
+
+ private final Object target;
+ private final Configuration configuration;
+ private final Interceptor interceptor;
+
+ public Plugin(Object target, Configuration configuration, Interceptor interceptor) {
+ this.target = target;
+ this.configuration = configuration;
+ this.interceptor = interceptor;
+ }
+
+ public static Object wrap(Object target, Configuration configuration, Interceptor interceptor) {
+ String pointcut = interceptor.pointcut();
+ PointcutDefinition definition = configuration.getPointcutRegistry().getDefinition(pointcut);
+ //不是当前接口类型不代理
+ if (!definition.getType().isAssignableFrom(target.getClass())) {
+ return target;
+ }
+ return Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class>[]{definition.getType()}, new Plugin(target, configuration, interceptor));
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ PointcutDefinition definition = configuration.getPointcutRegistry().getDefinition(interceptor.pointcut());
+ if (!Objects.equals(definition.getId(), PointcutDefinition.id(method))) {
+ //没有代理该方法,直接返回
+ return method.invoke(target, args);
+ }
+ return interceptor.intercept(new Invocation(target, method, args));
+ }
+}
diff --git a/src/main/java/org/apache/ibatis/session/Configuration.java b/src/main/java/org/apache/ibatis/session/Configuration.java
index c00a47e..ea4c3e9 100644
--- a/src/main/java/org/apache/ibatis/session/Configuration.java
+++ b/src/main/java/org/apache/ibatis/session/Configuration.java
@@ -18,6 +18,10 @@
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.InterceptorChain;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.PointcutRegistry;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.type.TypeHandlerRegistry;
@@ -37,6 +41,8 @@ public class Configuration {
private final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
private final LanguageDriver languageDriver = new XMLLanguageDriver();
private final Map resultMaps = new HashMap<>();
+ private final PointcutRegistry pointcutRegistry = new PointcutRegistry();
+ private final InterceptorChain interceptorChain = new InterceptorChain(this);
public Configuration() {
}
@@ -82,7 +88,9 @@ public void setDataSource(DataSource dataSource) {
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
- return new PrepareStatementHandler(executor, mappedStatement, parameterObject, boundSql);
+ StatementHandler statementHandler = new PrepareStatementHandler(executor, mappedStatement, parameterObject, boundSql);
+ statementHandler = interceptorChain.pluginAll(statementHandler);
+ return statementHandler;
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
@@ -108,4 +116,12 @@ public void addResultMap(ResultMap resultMap) {
public ResultMap getResultMap(String id) {
return resultMaps.get(id);
}
+
+ public PointcutRegistry getPointcutRegistry() {
+ return pointcutRegistry;
+ }
+
+ public void addInterceptor(Interceptor interceptor) {
+ interceptorChain.addInterceptor(interceptor);
+ }
}
diff --git a/src/test/java/org/apache/ibatis/plugin/PageInterceptor.java b/src/test/java/org/apache/ibatis/plugin/PageInterceptor.java
new file mode 100644
index 0000000..82d79d5
--- /dev/null
+++ b/src/test/java/org/apache/ibatis/plugin/PageInterceptor.java
@@ -0,0 +1,28 @@
+package org.apache.ibatis.plugin;
+
+import java.sql.Connection;
+
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+
+/**
+ * @author furious 2024/4/19
+ */
+public class PageInterceptor implements Interceptor {
+ @Override
+ public String pointcut() {
+ return PointcutRegistry.StatementHandler_prepare_Connection_Integer;
+ }
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ StatementHandler statementHandler = invocation.getTarget();
+ BoundSql original = statementHandler.getBoundSql();
+ Object[] args = invocation.getArgs();
+ Connection connection = (Connection) args[0];
+ //不判读是否为select语句,limit仅为示范参数
+ String sql = original.getSql();
+ sql += " LIMIT 1,1";
+ return connection.prepareStatement(sql);
+ }
+}
diff --git a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java
index d14dd7d..a8d31d8 100644
--- a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java
+++ b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java
@@ -7,6 +7,7 @@
import org.apache.ibatis.dao.UserMapper;
import org.apache.ibatis.entity.UserDO;
import org.apache.ibatis.entity.UserDTO;
+import org.apache.ibatis.plugin.PageInterceptor;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import org.junit.Assert;
import org.junit.Test;
@@ -158,6 +159,23 @@ public void queryForeachTag() {
Assert.assertNotNull(list);
}
+ @Test
+ public void queryPointcut() {
+ Configuration configuration = new Configuration();
+ configuration.addInterceptor(new PageInterceptor());
+ configuration.setDataSource(DataSourceBuilderTest.build());
+ configuration.addMapper(UserMapper.class);
+ SqlSession sqlSession = new DefaultSqlSession(configuration);
+ UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
+ List idList = new ArrayList<>();
+ idList.add(1L);
+ idList.add(2L);
+ List list = userMapper.listForeach(idList);
+ Assert.assertNotNull(list);
+ Assert.assertEquals(list.size(), 1);
+ }
+
+
private UserMapper getUserMapper() {
Configuration configuration = new Configuration();
configuration.setDataSource(DataSourceBuilderTest.build());