#插件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