Введение в Mybatis receptor
Mybatis обеспечивает функцию плагина. Хотя он называется плагином, это на самом деле функция перехвата. Так что же перехватывает перехватчик Mybatis?
Пойдем на официальный сайт, чтобы посмотреть:
Mybatis позволяет вам перехватывать вызовы в определенную точку во время выполнения сопоставленного оператора. По умолчанию метод вызовы Mybatis позволяет плагинам перехватить: включать:
Мы видели некоторые методы, которые могут перехватить интерфейс Executor, такие как обновление, запрос, коммит, откат и другие методы, а также некоторые методы других интерфейсов
ждать.
Общее резюме:
Использование перехватчиков
Interceptor Введение и конфигурация
Во -первых, давайте посмотрим на определение интерфейса Mybatis Interceptor:
Public Interface Interceptor {Object Intercept (вызов вызов) бросает бросание; Объектный плагин (цель объекта); void setProperties (свойства свойства);}Это относительно просто, есть только 3 метода. Mybatis не имеет класса реализации интерфейса Interceptor по умолчанию, и разработчики могут реализовать перехватчики, которые отвечают их потребностям.
Вот пример перехватчика с официального веб -сайта Mybatis:
@Intercepts ({@Signature (type = executor.class, method = "update", args = {mapedStatement.class, object.class})}) открытый класс Пример PLASTUGEN реализует receptor {public Object Intercept (vilpocation villocation) Throws {return vocation.proceed (); } public Object Plugin (объект Target) {return plugin.wrap (target, this); } public void setProperties (свойства свойств) {}}Глобальная конфигурация XML:
<blicins> <plugin receptor = "org.format.mybatis.cache.interceptor.exampleplugin"> </plugin> </plugins>
Этот перехватчик перехватывает метод обновления интерфейса исполнителя (на самом деле, это операции с добавлением, удалением и модификацией SQLSession). Все методы обновления, которые выполняют исполнителя, будут перехвачены перехватчиком.
Анализ исходного кода
Давайте проанализируем исходный код этого кода.
Во-первых, запустите анализ из файла Source-> config:
Xmlconfigbuilder sackses pluginelement Частный метод Mybatis Global Configuration File:
private void plaginelement (xnode parent) throws exception {if (parent! = null) {for (xnode child: parent.getchildren ()) {string receptor = child.getStringTtribute ("receptor"); Свойства свойства = child.getChildrenasProperties (); Interceptor InterceptorInstance = (Interceptor) Resolvalss (Interceptor) .newinStance (); receptorInstance.setProperties (свойства); configuration.addinterceptor (InterceptorInstance); }}}Конкретный код анализа на самом деле относительно прост, поэтому я не буду публиковать его. В основном он интенсирует класс, представленный атрибутом «перехватчика» в узле плагина путем отражения. Затем вызовите метод AddInterceptor Глобальной конфигурации класса конфигурации.
public void AddInterceptor (Interceptor Interceptor) {receptorChain.addinterceptor (Interceptor); }Этот InterceptorChain является внутренним свойством конфигурации, а его тип - InterceptorChain, которая является цепочкой перехвата. Давайте посмотрим на его определение:
Public Class InterceptorChain {Private Final List <Interceptor> Interceptors = new ArrayList <Interceptor> (); Public Object Plaginall (объект цели) {for (Interceptor Interceptor: Interceptors) {target = receptor.plugin (target); } return Target; } public void AddInterceptor (Interceptor Interceptor) {receptors.Add (Interceptor); } public list <Interceptor> getInterceptors () {return collections.unmodifiablelist (receptors); }}Теперь, когда мы понимаем анализ конфигурации перехватчика и владение перехватчиком, теперь мы оглядываемся на то, почему перехватчик перехватывает эти методы (частичные методы исполнителя, параметра -рук, результатыэндлер):
Public ParameterHandler newParameterHandler (отображение отображения Statement Statatement, объект ParameterObject, BoundsQl BoundsQL) {ParameterHandler parameterHandler = mapedStatement.getLang (). CreateParameterHandler (сопоставление Statatement, parameterObject, boundsQl); ParameterHandler = (parameterHandler) receptorChain.pluginall (parameterHandler); return parameterHandler;}public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, Boundsql, Rowbounds); ResultsEthandler = (Resultshandler) receptorChain.pluginall (ResultEthandler); return resultSetHandler;}public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, Boundsql); ratementHandler = (ratementHandler) receptorChain.pluginall (ratementHandler); return atportionHandler;} public Executor newexeCutor (транзакция транзакции, executortype exectortype, boolean autocommit) {executortype = executortype == null? defaultexecutortype: executortype; executortype = executortype == null? Exectortype.simple: executype; Исполнитель исполнителя; if (exectortype.batch == executortype) {experator = new batchexecutor (это, транзакция); } else if (recemortype.reuse == rexortortype) {rececutor = new reuseexecutor (это, транзакция); } else {executor = new SimpleExecutor (this, transaction); } if (cacheenabled) {executor = new cachingexecutor (Executor, AutoCommit); } executor = (исполнитель) receptorChain.pluginall (Executor); return Executor;}Приведенные выше 4 метода являются методами конфигурации. Эти методы будут выполняться в операции Mybatis (добавить, удалить, модифицировать и запросить). Порядок выполнения - исполнитель, Parameterhandler, Resultsethandler, WortingHandler (где параметры и результаты, создаются при создании оператора, [3 доступных классов реализации CallableStatementHandler, PreditStatementHandler, SimpleTateTatementHandler], и конструктор называет конструктор [конструкторы этих трех классов реализации фактически Calluctor Constructor ClassTortom
После того, как эти 4 метода создают экземпляр соответствующего объекта, они будут вызывать метод плагина InterceptorChain. Как упоминалось ранее, был введен плагин InterceptorChain, который должен пройти через все перехватчики, а затем вызовать метод плагина каждого перехватчика. ПРИМЕЧАНИЕ. Возвратное значение метода плагина перехватчика будет назначено непосредственно на исходный объект.
Поскольку утверждение -индлер может быть перехвачен, этот интерфейс в основном имеет дело со строительством синтаксиса SQL. Следовательно, например, функция пейджинга может быть реализована с помощью перехватчика. Вам необходимо только обработать SQL в классе реализации интерфейса athureHandler в методе плагина перехватчика, и вы можете использовать отражение для его реализации.
Mybatis также предоставляет аннотации для @Intercepts и @Signature о перехватчиках. Примером официального веб -сайта является использование этих двух аннотаций, включая использование класса плагинов:
@OverridePublic объекта плагин (объект цели) {return plugin.wrap (target, this);}Давайте проанализируем исходные коды этих 3 «новых комбинаций». Во -первых, давайте посмотрим на метод обертывания класса плагинов:
public static Object wrap (объект цели, Interceptor Interceptor) {map <class <?>, set <method >> signatureMap = getSignatureMap (receptor); Класс <?> Type = target.getClass (); Class <?> [] Интерфейсы = getallinterfaces (type, signatureMap); if (interfaces.length> 0) {return proxy.newProxyInstance (type.getClassLoader (), интерфейсы, новый плагин (Target, интерфейс, SignatureMap)); } return Target;}Класс плагина реализует интерфейс InvocationHandler. Очевидно, мы видим, что здесь возвращается динамичный класс прокси, предоставленный самим JDK. Давайте рассечь другие методы, называемые этим методом:
Метод GetsignatureMap:
Частная статическая карта <class <?>, set <method >> getSignaturemap (Interceptor Interceptor) {retercepts reterceptSannotation = receptor.getClass (). getAnnotation (retercepts.class); if (reterceptSannotation == null) {// Выпуск № 251 Throw New Pluginexception («Нет @Intercepts Annotation была найдена в Interceptor» + receptor.getClass (). getName ()); } Signature [] sigs = receptSannotation.value (); Map <class <?>, Set <method >> signatureMap = new hashmap <class <?>, Set <method >> (); for (signature sig: sigs) {set <method> methods = signatureMap.get (sig.type ()); if (methods == null) {methods = new hashset <method> (); signatureMap.put (sig.type (), методы); } try {method method = sig.type (). getMethod (sig.method (), sig.args ()); methods.add (метод); } catch (nosuchmethodexception e) {бросить новое плагинексапс («Не удалось найти метод на« + sig.type () + «именем" + sig.method () + ". Причина:" + e, e); }} return SignatureMap;}Пояснение метода GetsignatureMap: сначала вы получите аннотацию @Interceptors класса Interceptor, затем получите коллекцию аннотаций @Signature Antributes этого аннотации, затем пройдите эту коллекцию, выберите атрибут типа (тип класса) аннотации @Signature, а затем получите метод с атрибутом метода и атрибут ARGS, основанный на этом типе. Поскольку атрибут @Signature, аннотированный @Interceptors, является свойством, он в конечном итоге вернет карту с типом в качестве ключа и значения в качестве установленного <Метод>.
@Intercepts ({@Signature (type = executor.class, method = "update", args = {mapedstatement.class, object.class})})Например, аннотация @Interceptors вернет ключ в качестве исполнителя и значение в качестве коллекции (в этой коллекции есть только один элемент, то есть экземпляр метода, этот экземпляр метода является методом обновления интерфейса исполнителя, и этот метод имеет параметры типового отображения и объекта). Этот экземпляр метода получен на основе метода и атрибутов ARGS @Signature. Если параметр ARGS не соответствует методу метода типа, будет брошено исключение.
Метод GetallInterfaces:
Частный статический класс <?> [] getallinterfaces (class <?> type, map <class <?>, set <method >> signaturemap) {set <class <? >> интерфейсы = новый хэшсет <class <? >> (); while (type! = null) {for (class <?> c: type.getInterfaces ()) {if (signatureMap.containskey (c)) {interfaces.add (c); }} type = type.getSuperClass (); } return interfaces.toarray (новый класс <?> [interfaces.size ()]);}Объяснение метода GetallInterfaces: Согласно целевой цели экземпляра (эта цель - это класс, который Mybatis Interceptor может перехватывать, как упоминалось ранее, исполнитель, Parameterhandler, Resultsethandler, WortingHandler) и его родительские классы возвращают массив интерфейса, содержащий целевую реализацию в SignatureMap.
Следовательно, функция класса плагинов состоит в том, чтобы получить атрибут @Signature массива аннотированных атрибутов на основе аннотации @Interceptors, а затем использовать отражение, чтобы найти соответствующий метод в соответствии с типом, методом и атрибутами ARGS каждого аннотированного @Signature. Наконец, на основе интерфейса, реализованного CALL Target объектом, решите, вернуть ли прокси -объект для замены исходного целевого объекта.
Например, на официальном веб -сайте Mybatis, когда конфигурация вызывает метод NewExeCutor, метод обновления (MAPPSTatement MS, параметр объекта) интерфейса Executor перехватывается Interceptor. Таким образом, конец возвращается с плагином прокси -класса, а не исполнителем. При вызове метода таким образом, если это класс прокси, он будет выполнен:
public Object invoke (Object Proxy, Метод метода, Object [] args) бросает Throwable {try {set <Method> method = signatureMap.get (method.getDeclaringClass ()); if (methods! = null && methods.contains (method)) {return receptor.intercept (new Inpocation (Target, Method, Args)); } method return.invoke (target, args); } catch (Exception e) {throw ExceptionUtil.UnWrapThrowable (e); }}Правильно, если соответствующий метод найден и прокси -прокси -прокси, будет выполнен метод перехвата интерфейса Interceptor.
Этот класс вызова выглядит следующим образом:
Общедоступный класс inpocation {частное объект цели; Частный метод метод; частный объект [] args; public inpocation (цель объекта, метод метода, объект [] args) {this.Target = target; this.method = метод; this.args = args; } public Object getTarget () {return Target; } public Method getMethod () {return Method; } public Object [] getArgs () {return args; } public Object option () бросает vocationTargetException, allogalAccessException {return Method.invoke (target, args); }}Его метод процесса - вызов исходного метода (без прокси).
Суммировать
Среди 3 методов, предоставленных интерфейсом Mybatis Interceptor, метод плагина используется в процессе строительства определенных процессоров (обработчиков). Метод перехвата используется для обработки выполнения класса прокси. Метод SetProperties используется для установки свойств перехватчика.
Фактически, методы, предоставленные официальным веб -сайтом Mybatis для использования @Interceptors и @Signature Annotations и классов плагинов для обработки перехватчиков, не обязательно используются непосредственно таким образом. Мы также можем отказаться от этих трех классов и напрямую выполнять соответствующие операции на основе типа целевого экземпляра в методе плагина.
В целом, перехватчик Mybatis все еще очень прост. Сам перехватчик не требует слишком большого количества знаний, но изучение перехватчика требует знакомства с каждым интерфейсом в Mybatis, потому что перехватчик включает в себя точки знаний каждого интерфейса.
Суммировать
Вышесказанное - исследование принципов Mybatis Interceptor, представленного редактором. Я надеюсь, что это будет полезно для всех. Если у вас есть какие -либо вопросы, пожалуйста, оставьте мне сообщение, и редактор ответит всем вовремя. Большое спасибо за вашу поддержку сайту wulin.com!