Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand MyBatis dynamic Agent

2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "how to understand MyBatis dynamic agent". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to understand MyBatis dynamic agent".

Dynamic agent actual combat

As we all know, Mybatis underlying encapsulation uses JDK dynamic proxies. Before we talk about Mybatis dynamic agent, let's take a look at the dynamic agent Demo that we usually write.

Generally speaking, there are three steps to define a JDK dynamic proxy, as follows

Define proxy Interfac

Define a proxy interface implementation class

Define a dynamic proxy call handler

The three-step code is shown below, which can be understood by friends who have played with dynamic agents.

Public interface Subject {/ / define proxy interface String sayHello ();} public class SubjectImpl implements Subject {/ / define proxy interface implementation class @ Override public String sayHello () {System.out.println ("Hello World"); return "success";}} public class ProxyInvocationHandler implements InvocationHandler {/ / define dynamic proxy call processor private Object target Public ProxyInvocationHandler (Object target) {this.target = target;} @ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System.out.println ("? Enter the proxy call processor "); return method.invoke (target, args);}}

1. Write a test program, run it to see the effect, also in three steps

two。 Create an implementation class for the proxied interface

Create a dynamic proxy class and talk about three parameters

Class loader

An array of interfaces implemented by the proxy class

3. Use the processor (call the proxied class method, passing it every time)

The method is called by the proxy implementation class

Public class ProxyTest {public static void main (String [] args) {Subject subject = new SubjectImpl (); Subject proxy = (Subject) Proxy .newProxyInstance (subject.getClass () .getClassLoader (), subject.getClass () .getInterfaces (), new ProxyInvocationHandler (subject)); proxy.sayHello () / * * the printout is as follows * call the processor:? Enter the proxy call processor * proxied implementation class: Hello World * /}}

The Demo function has been implemented, and the general running process is clear. The following is to analyze the implementation of the principle.

Analysis of the principle of dynamic Agent

From the point of view of principle, how the above dynamic agent test program is executed

The first step is simple and straightforward, creating the implementation class of the Subject interface, which is also our regular implementation.

The second step is to create a dynamic proxy object for the proxied object. A friend here asked, how to prove that this is a dynamic proxy object? As shown in the figure

The name of the JDK dynamic proxy object is regular. For all dynamic proxy objects generated by the Proxy class, the prefix must be $Proxy, and the following numbers are also part of the name.

If a partner wants to find out and follow the inner class ProxyClassFactory of Proxy, here is the answer they want.

To get back to the point, let's take a look at ProxyInvocationHandler, which internally maintains a reference to the class implemented by the proxy interface, and the invoke method uses reflection to call the proxied interface to implement the class method.

You can see that the generated dynamic proxy class inherits the Proxy class, and then implements the Subject interface, while the implementation method sayHello actually calls the invoke method of ProxyInvocationHandler

Accidentally discovered the reason why the JDK dynamic agent can not proxy the class ^ ^

That is, when we call Subject#sayHello, the method call chain looks like this

However, there is an implementation class for the proxied interface in Demo, but not in Mybatis Mapper. How to play with this?

It doesn't matter if I don't know. I guess I won't see it if I know it. Let's take a look at how the mybatis source code plays.

Mybatis version:3.4.x

Mybatis source code implementation

I don't know if you have considered such a question, why doesn't Mybatis Mapper need to implement classes?

Let's say that our project uses a three-tier design, Controller controls request reception, Service handles business processing, and Mapper takes care of database interaction.

The Mapper layer, which is often referred to as the database mapping layer, is responsible for the operation of the database, such as querying or adding or deleting data.

Boldly imagine that the project does not use Mybatis, and needs to write database interaction in the Mapper implementation layer. What will be written?

Some regular JDBC operations will be written, such as:

/ / load Mysql driver Class.forName (driveName); / / get connection con = DriverManager.getConnection (url, user, pass); / / create Statement Statement state = con.createStatement (); / / build SQL statement String stuQuerySqlStr = "SELECT * FROM STUDENT"; / / execute SQL return result ResultSet result = state.executeQuery (stuQuerySqlStr);

If all the Mapper implementation layers in the project want to play like this, don't you really want to hit people?

So Mybatis combined with the pain point of the project came into being, how to do it?

All operations interacting with JDBC are encapsulated by JDK dynamic proxy at the bottom, and users only need to customize Mapper and .xml files.

The SQL statement is defined in an .xml file or Mapper. When the project starts, the parser parses the SQL statement and assembles it into objects in Java.

There are many parsers, because there are not only static statements but also dynamic SQL statements in Mybatis

This is why the Mapper interface does not need an implementation class, because it has been encapsulated by Mybatis through a dynamic proxy, and if there is an implementation class for each Mapper, it will be bloated and useless. After this operation, we are shown the Mybatis framework used in the project.

After laying the groundwork for so long, we are finally coming to the protagonist. Why can the Mybatis Mapper interface implement dynamic proxies without implementing classes?

It is almost impossible to introduce the Mybatis dynamic agent process in strict order without quoting unintroduced terms in advance. The author tries to make it easy to understand.

No implementation class completes dynamic proxy

Here comes the core point. Pick up the notebook and sit straight.

Let's first take a look at whether it is possible for ordinary dynamic agents to be done only by interfaces without implementing classes.

Public interface Subject {String sayHello ();} public class ProxyInvocationHandler implements InvocationHandler {@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System.out.println ("? enter the proxy call processor"); return "success";}}

As you can see from the code, we don't implement the interface Subject, so let's take a look at how to implement a dynamic proxy.

Public class ProxyTest {public static void main (String [] args) {Subject proxy = (Subject) Proxy .newProxyInstance (subject.getClass () .getClassLoader (), new Class [] {Subject.class}, new ProxyInvocationHandler ()); proxy.sayHello () / * * the printout is as follows * call the processor:? Enter the proxy call processor * /}}

As you can see, compared with the Demo at the beginning of the article, the parameters of the Proxy.newProxyInstance method have been changed.

Previously, we used to get the Class array of the implemented interface through the implementation class, but here we put the interface itself into the Class array, which goes the same way.

What is the difference between a dynamic proxy class generated by an implemented class interface and an unimplemented class interface?

The implemented class interface calls the InvocationHandler#invoke method, and the invoke method calls the proxied object (SubjectImpl) method (sayHello) through reflection.

The unimplemented class interface makes calls only to InvocationHandler#invoke. Therefore, the implemented class interface returns the return value of the proxied object interface, while the unimplemented class interface returns only the return value of the invoke method.

The return value of the InvocationHandler#invoke method is a success string, which defines whether a string variable can be returned successfully.

Now the answer to the first question has emerged. Mapper has no implementation class, and all operations such as calling JDBC are implemented in Mybatis InvocationHandler.

Now that the problem has been solved, it gives people the impression that it is not so difficult, but don't you wonder how the bottom layer of Mybatis does it?

First throw a question, and then take a question to see the source code, which may make you remember Double deeply.

The interface in our Demo is fixed, but the Mybatis Mapper is not fixed, how to do it?

That's what Mybatis said.

See how the dynamic interface proxy is implemented at the bottom of Mybatis. Partners only need to pay attention to the code at the tag.

Much like our Demo code, the core point is how mapperInterface is assigned.

First, let's talk about the concrete logic of generating dynamic proxy classes in the Mybatis proxy factory.

Based on the associated namespace on .xml, the Class object is returned by Class#forName reflection (not just .xml namespace)

Pass the resulting Class object (actually the interface object) to the Mybatis proxy factory to generate the proxy object, that is, the mapperInterface property just now

The answer is that Mybatis uses the fully qualified name of the interface to generate the Class object through Class#forName. This Class object type is the interface.

In order to facilitate everyone to understand, through the Mybatis source code provides an example of the test class. Assume that the existing interface AutoConstructorMapper and the corresponding .xml are as follows

Perform the first step to get the Class object according to the .xml namespace

The first step is to get the namespace attribute of the mapper tag on .xml and get the fully qualified information of the mapper interface.

Obtain Class objects based on mapper fully qualified information

Add it to the corresponding mapper container and wait for the dynamic proxy object to be generated

If you call to generate a dynamic proxy object at this time, the proxy factory newInstance method is as follows:

So far, all the questions related to Proxy and Mybatis dynamic agents mentioned at the beginning of the article have been answered.

Can abstract classes JDK dynamic proxies?

Say that the conclusion comes first before the code, no!

Public abstract class AbstractProxy {abstract void sayHello ();} AbstractProxy proxyInterface = (AbstractProxy) Proxy .newProxyInstance (ProxyTest.class.getClassLoader (), new Class [] {AbstractProxy.class}, new ProxyInvocationHandler ()); proxyInterface.sayHello ()

There is no doubt that it is inevitable to report an error. JDK cannot proxy a class.

With a little doubt, let's take a look at the error location of the Proxy source code. Will the JDK dynamic agent have interface verification in the process code for generating the proxy class?

Abstract class is a class after all, and adding an abstract cannot become an interface (like me, although I have gained 60 jin, I am still a handsome guy)

Next time, if the interviewer asks this question, be resolute, but you can't.

Conclusion

Combined with the problems related to the use of JDK dynamic agent by Mybatis, the article is described, which is summarized as follows.

Can Q:JDK dynamic proxies do class proxies?

Because the proxy class generated by the JDK dynamic proxy inherits the Proxy class, and because Java cannot inherit much, it cannot proxy the class.

Q: can abstract classes be dynamically proxied by JDK?

No, an abstract class is also a class in nature. In the process of generating a proxy class, Proxy will verify whether the incoming Class is an interface.

Q:Mybatis Mapper interface does not implement the class, how to implement the dynamic proxy?

Mybatis will get the Mapper interface Class object through Class#forname, generate the corresponding dynamic proxy object, and the core business processing will be processed in InvocationHandler#invoke.

Thank you for your reading, the above is the content of "how to understand MyBatis dynamic Agent". After the study of this article, I believe you have a deeper understanding of how to understand MyBatis dynamic Agent, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report