当前位置: 首页 > news >正文

wordpress网站无法访问wordpress 设置语言

wordpress网站无法访问,wordpress 设置语言,wordpress 首页关键词,开一家网站建设公司文章目录 一、目标#xff1a;Plugin插件二、设计#xff1a;Plugin插件三、实现#xff1a;Plugin插件3.1 工程结构3.2 Plugin插件代理模式类图3.3 自定义拦截注解3.3.1 方法签名3.3.2 拦截注解 3.4 拦截器接口定义3.4.1 调用信息3.4.2 拦截器接口 3.5 类代理包装操作3.5.1… 文章目录 一、目标Plugin插件二、设计Plugin插件三、实现Plugin插件3.1 工程结构3.2 Plugin插件代理模式类图3.3 自定义拦截注解3.3.1 方法签名3.3.2 拦截注解 3.4 拦截器接口定义3.4.1 调用信息3.4.2 拦截器接口 3.5 类代理包装操作3.5.1 获取签名方法3.5.2 创建反射代理3.5.3 包裹反射方法 3.6 拦截器链和配置项修改3.6.1 拦截器链3.6.2 配置项 3.7 解析XML插件配置 四、测试Plugin插件4.1 自定义插件4.2 修改XML配置文件4.3 单元测试 五、总结Plugin插件 一、目标Plugin插件 Mbatis Plugin的插件功能 Mybatis Plugin 的插件功能是非常重要的一个功能点包括我们可以结合插件的扩展分页、数据库表路由、监控日志等。这些核心功能的扩展都是来自于 Mybatis Plugin 提供对类的代理扩展并在代理中调用我们自定义插件的逻辑行为。对于插件的使用我们按照 Mybatis 框架提供的拦截器接口实现自己的功能实现类并把这个类配置到 Mybatis 的 XML 配置中。 二、设计Plugin插件 Mybatis Plugin 插件功能的实现设计 Mybatis Plugin 插件功能的实现设计也是一种 依赖倒置 的实现方式让插件的功能依赖于抽象接口不依赖于具体的实现。 这个过程中对抽象进行编程不对实现进行编程这样就降低了客户与实现模块间的耦合。 Mybatis Plugin 插件的具体实现落地由框架提供拦截器接口交由使用方实现并通过匹配的方式把实现添加到 Mybatis 框架中。 这样在具体的监听点上包括ParameterHandler、ResultSetHandler、StatementHandler、Executor。每一个创建过程中都可以把插件部分嵌入进去当调用任意类对应的接口方法时都能调用到用户实现拦截器接口的插件内容也就是实现类自定义扩展的效果。 以 XML 解析为入口解析用户自定义插件提取拦截器接口实现类保存到配置项的拦截器链对象中。接下来在创建语句处理器 StatementHandler 时使用代理的方式构建实现类并把拦截器作为对象中调用过程的一部分。那么这个拦截器的调用是一种方法过滤判断的方式通过拦截器实现类上配置的注解提取要拦截的方法。当 Mybatis 框架执行到这些节点时如调用 StatementHandler.prepare 方法时则进行拦截器执行用户扩展的插件操作。 三、实现Plugin插件 3.1 工程结构 mybatis-step-16 |-src|-main| |-java| |-com.lino.mybatis| |-annotations| | |-Delete.java| | |-Insert.java| | |-Select.java| | |-Update.java| |-binding| | |-MapperMethod.java| | |-MapperProxy.java| | |-MapperProxyFactory.java| | |-MapperRegistry.java| |-builder| | |-annotations| | | |-MapperAnnotationBuilder.java| | |-xml| | | |-XMLConfigBuilder.java| | | |-XMLMapperBuilder.java| | | |-XMLStatementBuilder.java| | |-BaseBuilder.java| | |-MapperBuilderAssistant.java| | |-ParameterExpression.java| | |-ResultMapResolver.java| | |-SqlSourceBuilder.java| | |-StaticSqlSource.java| |-datasource| | |-druid| | | |-DruidDataSourceFacroty.java| | |-pooled| | | |-PooledConnection.java| | | |-PooledDataSource.java| | | |-PooledDataSourceFacroty.java| | | |-PoolState.java| | |-unpooled| | | |-UnpooledDataSource.java| | | |-UnpooledDataSourceFacroty.java| | |-DataSourceFactory.java| |-executor| | |-keygen| | | |-Jdbc3KeyGenerator.java| | | |-KeyGenerator.java| | | |-NoKeyGenerator.java| | | |-SelectKeyGenerator.java| | |-parameter| | | |-ParameterHandler.java| | |-result| | | |-DefaultResultContext.java| | | |-DefaultResultHandler.java| | |-resultset| | | |-DefaultResultSetHandler.java| | | |-ResultSetHandler.java| | | |-ResultSetWrapper.java| | |-statement| | | |-BaseStatementHandler.java| | | |-PreparedStatementHandler.java| | | |-SimpleStatementHandler.java| | | |-StatementHandler.java| | |-BaseExecutor.java| | |-Executor.java| | |-SimpleExecutor.java| |-io| | |-Resources.java| |-mapping| | |-BoundSql.java| | |-Environment.java| | |-MappedStatement.java| | |-ParameterMapping.java| | |-ResultFlag.java| | |-ResultMap.java| | |-ResultMapping.java| | |-SqlCommandType.java| | |-SqlSource.java| |-parsing| | |-GenericTokenParser.java| | |-TokenHandler.java| |-plugin| | |-Interceptor.java| | |-InterceptorChain.java| | |-Intercepts.java| | |-Invocation.java| | |-Plugin.java| | |-Signature.java| |-reflection| | |-factory| | | |-DefaultObjectFactory.java| | | |-ObjectFactory.java| | |-invoker| | | |-GetFieldInvoker.java| | | |-Invoker.java| | | |-MethodInvoker.java| | | |-SetFieldInvoker.java| | |-property| | | |-PropertyNamer.java| | | |-PropertyTokenizer.java| | |-wrapper| | | |-BaseWrapper.java| | | |-BeanWrapper.java| | | |-CollectionWrapper.java| | | |-DefaultObjectWrapperFactory.java| | | |-MapWrapper.java| | | |-ObjectWrapper.java| | | |-ObjectWrapperFactory.java| | |-MetaClass.java| | |-MetaObject.java| | |-Reflector.java| | |-SystemMetaObject.java| |-scripting| | |-defaults| | | |-DefaultParameterHandler.java| | | |-RawSqlSource.java| | |-xmltags| | | |-DynamicContext.java| | | |-DynamicSqlSource.java| | | |-ExpressionEvaluator.java| | | |-IfSqlNode.java| | | |-MixedSqlNode.java| | | |-OgnlCache.java| | | |-OgnlClassResolver.java| | | |-SqlNode.java| | | |-StaticTextSqlNode.java| | | |-TextSqlNode.java| | | |-TrimSqlNode.java| | | |-XMLLanguageDriver.java| | | |-XMLScriptBuilder.java| | |-LanguageDriver.java| | |-LanguageDriverRegistry.java| |-session| | |-defaults| | | |-DefaultSqlSession.java| | | |-DefaultSqlSessionFactory.java| | |-Configuration.java| | |-ResultContext.java| | |-ResultHandler.java| | |-RowBounds.java| | |-SqlSession.java| | |-SqlSessionFactory.java| | |-SqlSessionFactoryBuilder.java| | |-TransactionIsolationLevel.java| |-transaction| | |-jdbc| | | |-JdbcTransaction.java| | | |-JdbcTransactionFactory.java| | |-Transaction.java| | |-TransactionFactory.java| |-type| | |-BaseTypeHandler.java| | |-DateTypeHandler.java| | |-IntegerTypeHandler.java| | |-JdbcType.java| | |-LongTypeHandler.java| | |-SimpleTypeRegistry.java| | |-StringTypeHandler.java| | |-TypeAliasRegistry.java| | |-TypeHandler.java| | |-TypeHandlerRegistry.java|-test|-java| |-com.lino.mybatis.test| |-dao| | |-IActivityDao.java| |-plugin| | |-TestPlugin.java| |-po| | |-Activity.java| |-ApiTest.java|-resources|-mapper| |-Activity_Mapper.xml|-mybatis-config-datasource.xml3.2 Plugin插件代理模式类图 首先是以扩展 XMLConfigBuilder 解析自定义插件配置将自定义插件写入配置项的拦截器链中。而每一个用户实现的拦截器接口都包装了插件的代理操作。 这就像是一个代理器的盒子把原有类的行为和自定义的插件行为使用代理包装到一个调度方法中。 接下来是对自定义插件的激活部分也就是把这个插件的调用挂在哪个节点下。 这里通过在 Configuration 配置项在创建各类操作时把自定义插件嵌入进去。 基于 StatementHandler 创建语句处理器时使用拦截器链将定义插件包裹到 StatementHandler 目标方法中这样在后续调用 StatementHandler 的方法时就顺便调用自定义实现的拦截器了。 3.3 自定义拦截注解 关于 Mybatis Plugin 插件的使用需要实现 Interceptor 拦截器接口完成使用方自身功能的扩展。但也需要基于注解来指定需要在哪个类的哪个方法下做调用处理。 例如Intercepts({Signature(type StatementHandler.class, method prepare, args {Connection.class})})这就是一个插件实现类上的注解指定了在 StatementHandler 语句处理器调用入参为 Connection 的 prepare 方法准备语句阶段完成自定义插件的处理。 3.3.1 方法签名 Signature.java package com.lino.mybatis.plugin;/*** description: 方法签名*/ public interface Signature {/*** 被拦截类*/Class? type();/*** 被拦截类的方法*/String method();/*** 被拦截类的方法的参数*/Class?[] args(); }Signature 方法签名接口定义了被拦截类的 type也就是如我们拦截 StatementHandler 语句处理器。另外就是在这个类下需要根据方法名称和参数来确定是这个类下的哪个方法只有这2个信息都存在才能确定唯一类下的方法。 3.3.2 拦截注解 Intercepts.java package com.lino.mybatis.plugin;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** description: 拦截注解*/ Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Intercepts {Signature[] value(); }Intercepts 注解一个目的是作为标记存在所有的插件实现都需要有这个自定义的注解标记。另外这个注解中还有另外一个注解的存在就是方法签名注解用于定位需要在哪个类的哪个方法下完成插件的调用。 3.4 拦截器接口定义 需要定义一个拦截器接口这个是面向抽象编程的依赖倒置的入口插件只定义标准具体调用处理结果交由使用方决定。 3.4.1 调用信息 Invocation.java package com.lino.mybatis.plugin;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;/*** description: 调用信息*/ public class Invocation {/*** 调用的对象*/private Object target;/*** 调用的方法*/private Method method;/*** 调用的参数*/private Object[] args;public Invocation(Object target, Method method, Object[] args) {this.target target;this.method method;this.args args;}public Object getTarget() {return target;}public Method getMethod() {return method;}public Object[] getArgs() {return args;}/*** 放行调用执行** return 对象* throws InvocationTargetException 调用对象异常* throws IllegalAccessException 异常*/public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);} }3.4.2 拦截器接口 Interceptor.java package com.lino.mybatis.plugin;import java.util.Properties;/*** description: 拦截器接口*/ public interface Interceptor {/*** 拦截使用方实现** param invocation 调用信息* return 对象* throws Throwable*/Object intercept(Invocation invocation) throws Throwable;/*** 代理** param target 代理对象* return Object*/default Object plugin(Object target) {return Plugin.wrap(target, this);}/*** 设置属性** param properties 属性*/default void setProperties(Properties properties) {// NOP} }Interceptor 提供了3个方法一个 intercept 方法是交由使用方实现的另外2个算是 default 方法使用方不需要做实现。这样每一个 Interceptor 的实现类就都通过解析的方式注册到拦截器链中在后续需要基于 StatementHandler 语句处理器创建时就可以通过代理的方式把自定义插件包装到代理方法中。setProperties 方法是属性处理相当于可以把用户配置到 XML 下插件中的属性信息通过这里传递。 3.5 类代理包装操作 插件的实现核心逻辑就在 Plugin 插件这个类下处理的。Plugin 通过实现 InvocationHandler 代理接口在 invoke 方法中包装对插件的处理。当任何一个被代理的类包括ParameterHandler、ResultSetHandler、StatementHandler、Executor在执行方法调用时就可以调用到用户自定义的插件。 Plugin.java package com.lino.mybatis.plugin;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;/*** description: 代理模式插件*/ public class Plugin implements InvocationHandler {private Object target;private Interceptor interceptor;private MapClass?, SetMethod signatureMap;public Plugin(Object target, Interceptor interceptor, MapClass?, SetMethod signatureMap) {this.target target;this.interceptor interceptor;this.signatureMap signatureMap;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取声明的方法列表SetMethod methods signatureMap.get(method.getDeclaringClass());// 过滤需要拦截的方法if (methods ! null methods.contains(method)) {// 调用 Interceptor#intercept 插入自己的反射逻辑return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args);}/*** 用代理把自定义插件行为包裹到目标方法中也就是 Plugin.invoke 的过滤调用** param target 调用对象* param interceptor 拦截器接口* return 返回对象*/public static Object wrap(Object target, Interceptor interceptor) {// 取得签名MapClass?, SetMethod signatureMap getSignatureMap(interceptor);// 取得要改变行为的类(ParameterHandler|ResultSetHandler|StatementHandler|Executor)目前只添加了 StatementHandlerClass? type target.getClass();// 取得接口Class?[] interfaces getAllInterfaces(type, signatureMap);// 创建代理(StatementHandler)if (interfaces.length 0) {// Proxy.newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h)return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}/*** 获取方法签名组 Map** param interceptor 拦截器接口* return 方法签名组 Map*/private static MapClass?, SetMethod getSignatureMap(Interceptor interceptor) {// 取得 Intercepts 注解例子可参见 TestPlugin.javaIntercepts interceptsAnnotation interceptor.getClass().getAnnotation(Intercepts.class);// 必须得有 Intercepts 注释没有报错if (interceptsAnnotation null) {throw new RuntimeException(No Intercepts annotation was found in interceptor interceptor.getClass().getName());}// value是数组型Signature的数组Signature[] sigs interceptsAnnotation.value();// 每个 class 类有多个可能有多个 Method 需要被拦截MapClass?, SetMethod signatureMap new HashMap(16);for (Signature sig : sigs) {SetMethod methods signatureMap.computeIfAbsent(sig.type(), k - new HashSet());try {// 例如获取到方法StatementHandler.prepare(Connection connection)、StatementHandler.parameterize(Statement statement)...Method method sig.type().getMethod(sig.method(), sig.args());methods.add(method);} catch (NoSuchMethodException e) {throw new RuntimeException(Could not find method on sig.type() named sig.method() . Cause: e, e);}}return signatureMap;}/*** 获取接口** param type 类类型* param signatureMap 方法签名组 Map* return 接口列表*/private static Class?[] getAllInterfaces(Class? type, MapClass?, SetMethod signatureMap) {SetClass? interfaces new HashSet();while (type ! null) {for (Class? c : type.getInterfaces()) {// 拦截 ParameterHandler|ResultSetHandler|StatementHandler|Executorif (signatureMap.containsKey(c)) {interfaces.add(c);}}type type.getSuperclass();}return interfaces.toArray(new Class?[0]);} }3.5.1 获取签名方法 /*** 获取方法签名组 Map** param interceptor 拦截器接口* return 方法签名组 Map*/ private static MapClass?, SetMethod getSignatureMap(Interceptor interceptor) {// 取得 Intercepts 注解例子可参见 TestPlugin.javaIntercepts interceptsAnnotation interceptor.getClass().getAnnotation(Intercepts.class);// 必须得有 Intercepts 注释没有报错if (interceptsAnnotation null) {throw new RuntimeException(No Intercepts annotation was found in interceptor interceptor.getClass().getName());}// value是数组型Signature的数组Signature[] sigs interceptsAnnotation.value();// 每个 class 类有多个可能有多个 Method 需要被拦截MapClass?, SetMethod signatureMap new HashMap(16);for (Signature sig : sigs) {SetMethod methods signatureMap.computeIfAbsent(sig.type(), k - new HashSet());try {// 例如获取到方法StatementHandler.prepare(Connection connection)、StatementHandler.parameterize(Statement statement)...Method method sig.type().getMethod(sig.method(), sig.args());methods.add(method);} catch (NoSuchMethodException e) {throw new RuntimeException(Could not find method on sig.type() named sig.method() . Cause: e, e);}}return signatureMap; }getSignatureMap 所完成的动作就是为了获取代理类的签名操作返回这个类下在哪个方法下执行调用插件操作。 根据入参 Interceptor 的接口的实现从实现类的注解上获取方法的签名信息。方法签名可以是一个数组结构也就是一个插件可以监听多个配置的类以及多个类内的方法当这些类的方法被调用的时候就会调用到执行的自定义插件。而在这个方法下把符合监听方法返回一个列表用于代理类中判断是否调用插件。 3.5.2 创建反射代理 /*** 用代理把自定义插件行为包裹到目标方法中也就是 Plugin.invoke 的过滤调用** param target 调用对象* param interceptor 拦截器接口* return 返回对象*/ public static Object wrap(Object target, Interceptor interceptor) {// 取得签名MapClass?, SetMethod signatureMap getSignatureMap(interceptor);// 取得要改变行为的类(ParameterHandler|ResultSetHandler|StatementHandler|Executor)目前只添加了 StatementHandlerClass? type target.getClass();// 取得接口Class?[] interfaces getAllInterfaces(type, signatureMap);// 创建代理(StatementHandler)if (interfaces.length 0) {// Proxy.newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h)return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target; }wrap 方法是用于给 ParameterHandler、ResultSetHandler、StatementHandler、Executor 创建代理类时调用的。 这个创建的目的就是把插件内容包装到代理中。 代理的创建是通过 Proxy.newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler handler 实现的。 而入参 InvocationHandler 的实现类则是这个 Plugin 代理插件实现类。 3.5.3 包裹反射方法 Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取声明的方法列表SetMethod methods signatureMap.get(method.getDeclaringClass());// 过滤需要拦截的方法if (methods ! null methods.contains(method)) {// 调用 Interceptor#intercept 插入自己的反射逻辑return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args); }最终对于插件的核心调用都会体现到 invoke 方法中。如一个被代理的类 ParameterHandler 当调用它的方法时都会进入 invoke中。 在 invoker 方法中通过前面方法的判断确定使用方自己实现的插件是否在此时调用的方法上。如果是则进入插件调用插件的实现中处理完自己的逻辑则进行 invocation.proceed() 放行。如果不在这个方法上则直接通过 method.invoke(target, args) 调用原本的方法即可。 3.6 拦截器链和配置项修改 3.6.1 拦截器链 InterceptorChain package com.lino.mybatis.plugin;import java.util.ArrayList; import java.util.Collections; import java.util.List;/*** description: 拦截器链*/ public class InterceptorChain {private final ListInterceptor interceptors new ArrayList();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public ListInterceptor getInterceptors() {return Collections.unmodifiableList(interceptors);} }3.6.2 配置项 Configuration.java package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry; import com.lino.mybatis.datasource.druid.DruidDataSourceFactory; import com.lino.mybatis.datasource.pooled.PooledDataSourceFactory; import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory; import com.lino.mybatis.executor.Executor; import com.lino.mybatis.executor.SimpleExecutor; import com.lino.mybatis.executor.keygen.KeyGenerator; import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.executor.resultset.DefaultResultSetHandler; import com.lino.mybatis.executor.resultset.ResultSetHandler; import com.lino.mybatis.executor.statement.PreparedStatementHandler; import com.lino.mybatis.executor.statement.StatementHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.Environment; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.mapping.ResultMap; import com.lino.mybatis.plugin.Interceptor; import com.lino.mybatis.plugin.InterceptorChain; import com.lino.mybatis.reflection.MetaObject; import com.lino.mybatis.reflection.factory.DefaultObjectFactory; import com.lino.mybatis.reflection.factory.ObjectFactory; import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory; import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory; import com.lino.mybatis.scripting.LanguageDriver; import com.lino.mybatis.scripting.LanguageDriverRegistry; import com.lino.mybatis.scripting.xmltags.XMLLanguageDriver; import com.lino.mybatis.transaction.Transaction; import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory; import com.lino.mybatis.type.TypeAliasRegistry; import com.lino.mybatis.type.TypeHandlerRegistry; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;/*** description: 配置项*/ public class Configuration {.../*** 结果映射存在Map里*/protected final MapString, ResultMap resultMaps new HashMap(16);/*** 键值生成器存在Map里*/protected final MapString, KeyGenerator keyGenerators new HashMap(16);/*** 插件拦截器链*/protected final InterceptorChain interceptorChain new InterceptorChain();.../*** 创建语句处理器** param executor 执行器* param mappedStatement 映射器语句类* param parameter 参数* param rowBounds 分页记录限制* param resultHandler 结果处理器* param boundSql SQL语句* return StatementHandler 语句处理器*/public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter,RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {StatementHandler statementHandler new PreparedStatementHandler(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);// 嵌入插件代理对象statementHandler (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}...public void addInterceptor(Interceptor interceptorInstance) {interceptorChain.addInterceptor(interceptorInstance);} }在 newStatementHandler 方法中嵌入插件代理对象。 3.7 解析XML插件配置 接下来需要在 XML Config 的解析操作中添加关于插件部分的解析处理也就是处理配置在 mybatis-config-datasource.xml 中插件的信息 pluginsplugin interceptorcom.lino.mybatis.test.plugin.TestPluginproperty nametest00 value100/property nametest01 value200//plugin /plugins这部分解析处理 interceptor 是自定义插件的实现类property 两个属性信息通常是不需要使用的。这里是为了测试需要。 XMLConfigBuilder.java package com.lino.mybatis.builder.xml;import com.lino.mybatis.builder.BaseBuilder; import com.lino.mybatis.datasource.DataSourceFactory; import com.lino.mybatis.io.Resources; import com.lino.mybatis.mapping.Environment; import com.lino.mybatis.plugin.Interceptor; import com.lino.mybatis.session.Configuration; import com.lino.mybatis.transaction.TransactionFactory; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.xml.sax.InputSource; import javax.sql.DataSource; import java.io.InputStream; import java.io.Reader; import java.util.List; import java.util.Properties;/*** description: XML配置构建器建造者模式集成BaseBuilder*/ public class XMLConfigBuilder extends BaseBuilder {.../*** 解析配置类型别名、插件、对象工厂、对象包装工厂、设置、环境、类型转换、映射器** return Configuration*/public Configuration parse() {try {// 插件添加pluginElement(root.element(plugins));// 环境environmentsElement(root.element(environments));// 解析映射器mapperElement(root.element(mappers));} catch (Exception e) {throw new RuntimeException(Error parsing SQL Mapper Configuration. Cause: e, e);}return configuration;}/*** Mybatis 允许你在某一点切入映射语句执行的调度* plugins* plugin interceptorcn.bugstack.mybatis.test.plugin.TestPlugin* property nametest00 value100/* property nametest01 value100/* /plugin* /plugins*/private void pluginElement(Element parent) throws Exception {if (parent null) {return;}ListElement elements parent.elements();for (Element element : elements) {String interceptor element.attributeValue(interceptor);// 参数配置Properties properties new Properties();ListElement propertyElementList element.elements(property);for (Element property : propertyElementList) {properties.setProperty(property.attributeValue(name), property.attributeValue(value));}// 获取插件实现类并实例化com.lino.mybatis.test.plugin.TestPluginInterceptor interceptorInstance (Interceptor) resolveAlias(interceptor).newInstance();interceptorInstance.setProperties(properties);configuration.addInterceptor(interceptorInstance);}}...}解析插件的处理需要判断插件是否存在如果存在则按照插件配置的列表分别进行解析提取配置中的接口信息以及属性配置存放到 Configuration 配置的插件拦截器链中。通过这样的方式把插件和要触发的监控点建立起连接。解析流程在解析方法提供后则放入到顺序解析的操作方法中即可。XMLConfigBuilder#pluginElement(root.element(plugins)) 四、测试Plugin插件 4.1 自定义插件 TestPlugin.java package com.lino.mybatis.test.plugin;import com.lino.mybatis.executor.statement.StatementHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.plugin.Interceptor; import com.lino.mybatis.plugin.Intercepts; import com.lino.mybatis.plugin.Invocation; import com.lino.mybatis.plugin.Signature; import java.sql.Connection; import java.util.Properties;/*** description: 测试插件*/ Intercepts({Signature(type StatementHandler.class, method prepare, args {Connection.class})}) public class TestPlugin implements Interceptor {Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取 StatementHandlerStatementHandler statementHandler (StatementHandler) invocation.getTarget();// 获取SQL信息BoundSql boundSql statementHandler.getBoundSql();String sql boundSql.getSql();// 输出SQLSystem.out.println(拦截SQL sql);// 放行return invocation.proceed();}Overridepublic void setProperties(Properties properties) {System.out.println(参数输出 properties.getProperty(test00));} }TestPlugin 自定义插件实现 Interceptor 接口同时通过注解 Intercepts 配置插件的触发时机。这里则是在调用 StatementHandler#prepare 方法时处理自定义插件的操作。在这个自定义插件中获取到 StatementHandler 语句处理器下的绑定 SQL 信息。 注意这个 StatementHandler#getBoundSql 获取绑定 SQL 方法是新增的方法。 另外是实现了 setProperties 获取注解的操作这里是打印注解配置的信息。 4.2 修改XML配置文件 mybatis-config-datasource.xml ?xml version1.0 encodingUTF-8? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd configurationpluginsplugin interceptorcom.lino.mybatis.test.plugin.TestPluginproperty nametest00 value100/property nametest01 value200//plugin/pluginsenvironments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.jdbc.Driver/property nameurlvaluejdbc:mysql://127.0.0.1:3306/mybatis?useUnicodetrueamp;characterEncodingutf8/property nameusername valueroot/property namepassword value123456//dataSource/environment/environmentsmappers!--XML配置--mapper resourcemapper/Activity_Mapper.xml//mappers /configuration4.3 单元测试 ApiTest.java Test public void test_queryActivityById() {// 1.获取映射器对象IActivityDao dao sqlSession.getMapper(IActivityDao.class);// 2.测试验证Activity activity new Activity();activity.setActivityId(100001L);Activity result dao.queryActivityById(activity);logger.info(测试结果{}, JSON.toJSONString(result)); }测试结果 参数输出100 16:52:51.437 [main] INFO c.l.m.d.pooled.PooledDataSource - Created connention 1164440413. 拦截SQLSELECT activity_id, activity_name, activity_desc, create_time, update_timeFROM activitywhere activity_id ? 16:52:51.446 [main] INFO c.l.m.s.d.DefaultParameterHandler - 根据每个ParameterMapping中的TypeHandler设置对应的参数信息 value100001 16:52:51.454 [main] INFO com.lino.mybatis.test.ApiTest - 测试结果{activityDesc:测试活动,activityId:100001,activityName:活动名,createTime:1628424890000,updateTime:1628424890000}通过测试结果看插件功能的实现已经验证通过。 五、总结Plugin插件 本章是对代理模式的最佳实践通过代理对一个目标监听方法中完成对扩展内容的调用。 而这个扩展内容则是根据依赖倒置原则面向抽象编程的具体实现。 当一个框架逐步开发完成后就要开始逐步对外提供扩展能力了这样才能更好的让一个框架满足不同类用户的扩展需求。 所以我们在做一些业务代码开发时也应该给扩展留出口子让后续的迭代更加容易也更易于维护。
http://www.zqtcl.cn/news/453148/

相关文章:

  • 新网网站空间到期停了 咋续费网站营销推广应该怎么做
  • 网站建设和编辑实训报告安卓版网页制作软件
  • 网站模板框架站长资讯
  • 上海做网站哪家公司2022年国际国内重大新闻
  • 网站建设如何定位网站建设思路方向
  • 手机网站拦截怎么解除网站生成软件免费制作
  • 中国房地产网站茂名住房和城乡建设厅网站
  • 做网站销售工资怎么样网页设计是哪个专业
  • 吉林省住房城乡建设厅网站首页微商城模板包含哪些
  • 优秀个人网站案例wordpress 文章格式
  • 2019年做网站装修平面设计图的制作
  • 潍坊网站建设top淘宝客网站名
  • 怎么给网站做外链网上接效果图平台
  • 电影网站建设教程下载怎么经营团购网站
  • 做网站卖什么建设银信用卡网站首页
  • 大连市城乡建设档案馆网站网上竞价采购网站建设
  • 国际物流公司网站建设浏览器正能量网站免费图片
  • 河南做外贸网站的公司怎么做家庭网站
  • 知名营销类网站互联网软件开发是什么工作
  • 做网站前新闻录入网站模板
  • 网站域名做跳转要收费吗科技信息期刊
  • 登别的网站应怎么做网站推广广告词大全集
  • 漯河城乡建设管理局网站wordpress icon class
  • 买空间哪个网站好广州多少网络科技有限公司
  • 网站的网络推广方案营销型网站建设论文
  • 苏州做网站便宜的公司哪家好门店管理系统app
  • 学校多语言网站建设网络维护网站建设培训
  • Wordpress外贸网站搭建公司建站系统的应用场景
  • 网站推广网络推广方wordpress汉语公益
  • 长沙做网站的公司有哪些宁波奉化建设局网站