#插件java
MyBatis中使用插件,咱们必须实现Interceptor接口,接口的代码以下:apache
package org.apache.ibatis.plugin; import java.util.Properties; public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); }
intercept():它将直接覆盖你所拦截对象原有的方法,所以它是插件的核心方法。intercept里面有个参数Invocation对象,经过它能够反射调度原来的对象的方法。性能
plugin():里面的参数Object target是被拦截的对象,它的做用是给被拦截对象生成一个代理对象,而且返回它。在MyBatis里直接使用org.apache.ibatis.plugin.Plugin中的wrap静态(static)方法提供了生成代理对象,咱们每每使用plugin方法即可以生成一个代理对象了。ui
public static Object wrap(Object target, Interceptor interceptor) { Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; }
setProperties():容许在plugin元素中配置咱们须要的参数,方法在插件初始化的时候就会被调用一次,而后把插件对象存入到配置中,方便后面获取。 在org.apache.ibatis.builder.xml.XMLConfigBuilder咱们能够看到: private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } }.net
其实在解析配置文件的过程当中,咱们的插件节点和咱们配置参数,同时使用反射技术生成对应的插件实例,而后调用插件方法中的setProperties(),设置咱们配置的参数,而后将插件实例保存到配置对象里,方便后面的读取使用它。因此插件的实例对象是以开始就被初始化的,不是在使用到的时候才初始化,这样能够提高性能。插件
Configuration保存插件的方式(初始化完的参数保存在了List<Interceptor> interceptors这个list里面):代理
public void addInterceptor(Interceptor interceptor) { interceptorChain.addInterceptor(interceptor); }
public class InterceptorChain { private final List<Interceptor> interceptors = new ArrayList<Interceptor>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List<Interceptor> getInterceptors() { return Collections.unmodifiableList(interceptors); } }
Plugin类的plugin()能够生成代理对象,在生成代理对象以后将对象存进了Configuration里面,若是须要直接从Configuration实例获取就能够了。从第一个对象(四大对象中的一个)开始,将对象传递给plugin(),而后返回一个代理;若是存在第二个插件,那么咱们拿到第一个代理对象,传递给plugin()再返回第一个代理独享的代理......依此类推,拦截器越多,代理的对象就越多(多少个拦截器就多少个代理对象)。保证了每个插件均可以拦截到真是的对象。这就号比每个插件均可以一层层的处理拦截的对象。MyBatis的四大对象也是如此处理的。code