Skip to content

Commit

Permalink
Merge pull request #9 from FuriousPws002/08-plugin
Browse files Browse the repository at this point in the history
插件支持
  • Loading branch information
FuriousPws002 authored Apr 19, 2024
2 parents 0261e21 + be1213d commit f86e64e
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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") <br>
[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") <br>
[7.动态sql](https://github.com/FuriousPws002/mini-mybatis/wiki/7.%E5%8A%A8%E6%80%81sql "Markdown") <br>
[8.插件支持](https://github.com/FuriousPws002/mini-mybatis/wiki/8.%E6%8F%92%E4%BB%B6%E6%94%AF%E6%8C%81 "Markdown") <br>
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ public <T> List<T> query(Statement statement) throws SQLException {
ps.execute();
return resultSetHandler.handleResultSets(ps);
}

@Override
public BoundSql getBoundSql() {
return boundSql;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.mapping.BoundSql;

/**
* @author furious 2024/4/8
*/
Expand All @@ -17,4 +19,6 @@ public interface StatementHandler {
void parameterize(Statement statement) throws SQLException;

<T> List<T> query(Statement statement) throws SQLException;

BoundSql getBoundSql();
}
17 changes: 17 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/Interceptor.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
30 changes: 30 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/InterceptorChain.java
Original file line number Diff line number Diff line change
@@ -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<Interceptor> interceptors = new ArrayList<>();

public InterceptorChain(Configuration configuration) {
this.configuration = configuration;
}

public <T> T pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target, configuration);
}
return (T) target;
}

public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
}
35 changes: 35 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/Invocation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.apache.ibatis.plugin;

import java.lang.reflect.Method;

/**
* @author furious 2024/4/18
*/
public class Invocation {

private final Object target;
private final Method method;
private final Object[] args;

public Invocation(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}

public <T> T getTarget() {
return (T)target;
}

public Method getMethod() {
return method;
}

public Object[] getArgs() {
return args;
}

public <T> T proceed() throws Exception {
return (T)method.invoke(target, args);
}
}
44 changes: 44 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/Plugin.java
Original file line number Diff line number Diff line change
@@ -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));
}
}
44 changes: 44 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/PointcutDefinition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.apache.ibatis.plugin;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
* @author furious 2024/4/18
*/
public class PointcutDefinition {

private final Class<?> type;
private final Method method;
private final Class<?>[] args;
private final String id;

public PointcutDefinition(Method method, PointcutRegistry registry) {
this.type = method.getDeclaringClass();
this.method = method;
this.args = method.getParameterTypes();
this.id = id(method);
registry.getDefinitions().put(id, this);
}

public static String id(Method method) {
return String.join("_", method.getDeclaringClass().getSimpleName(), method.getName(), Arrays.stream(method.getParameterTypes()).map(Class::getSimpleName).collect(Collectors.joining("_")));
}

public Class<?> getType() {
return type;
}

public Method getMethod() {
return method;
}

public Class<?>[] getArgs() {
return args;
}

public String getId() {
return id;
}
}
44 changes: 44 additions & 0 deletions src/main/java/org/apache/ibatis/plugin/PointcutRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.apache.ibatis.plugin;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;

/**
* @author furious 2024/4/18
*/
public class PointcutRegistry {

public static final String Executor_update_MappedStatement_Object = "Executor_update_MappedStatement_Object";
public static final String Executor_query_MappedStatement_Object = "Executor_query_MappedStatement_Object";
public static final String ParameterHandler_getParameterObject_ = "ParameterHandler_getParameterObject_";
public static final String ParameterHandler_setParameters_PreparedStatement = "ParameterHandler_setParameters_PreparedStatement";
public static final String ResultSetHandler_handleResultSets_Statement = "ResultSetHandler_handleResultSets_Statement";
public static final String StatementHandler_parameterize_Statement = "StatementHandler_parameterize_Statement";
public static final String StatementHandler_update_Statement = "StatementHandler_update_Statement";
public static final String StatementHandler_prepare_Connection_Integer = "StatementHandler_prepare_Connection_Integer";
public static final String StatementHandler_query_Statement = "StatementHandler_query_Statement";
public static final String StatementHandler_getBoundSql_ = "StatementHandler_getBoundSql_";

private final Map<String, PointcutDefinition> definitions = new LinkedHashMap<>();

public PointcutRegistry() {
Arrays.stream(Executor.class.getMethods()).forEach(m -> new PointcutDefinition(m, this));
Arrays.stream(ParameterHandler.class.getMethods()).forEach(m -> new PointcutDefinition(m, this));
Arrays.stream(ResultSetHandler.class.getMethods()).forEach(m -> new PointcutDefinition(m, this));
Arrays.stream(StatementHandler.class.getMethods()).forEach(m -> new PointcutDefinition(m, this));
}

public Map<String, PointcutDefinition> getDefinitions() {
return definitions;
}

public PointcutDefinition getDefinition(String key) {
return definitions.get(key);
}
}
18 changes: 17 additions & 1 deletion src/main/java/org/apache/ibatis/session/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,6 +41,8 @@ public class Configuration {
private final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
private final LanguageDriver languageDriver = new XMLLanguageDriver();
private final Map<String, ResultMap> resultMaps = new HashMap<>();
private final PointcutRegistry pointcutRegistry = new PointcutRegistry();
private final InterceptorChain interceptorChain = new InterceptorChain(this);

public Configuration() {
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
}
28 changes: 28 additions & 0 deletions src/test/java/org/apache/ibatis/plugin/PageInterceptor.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
18 changes: 18 additions & 0 deletions src/test/java/org/apache/ibatis/session/SqlSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Long> idList = new ArrayList<>();
idList.add(1L);
idList.add(2L);
List<UserDO> list = userMapper.listForeach(idList);
Assert.assertNotNull(list);
Assert.assertEquals(list.size(), 1);
}


private UserMapper getUserMapper() {
Configuration configuration = new Configuration();
configuration.setDataSource(DataSourceBuilderTest.build());
Expand Down

0 comments on commit f86e64e

Please sign in to comment.