preface
If someone asks you these questions, see if you can answer them
- Mybatis Mapper interface does not implement class, how to implement SQL query
- JDK dynamic proxy can not be used to proxy classes.
- JDK Dynamic proxies for abstract classes (additional questions)
Can not answer the iron juice, Proxy, Mybatis source code has not seen a bit. But it doesn’t matter, continue to read to understand
Dynamic proxy combat
As you know, Mybatis is a JDK dynamic proxy used by the underlying package. Before saying Mybatis dynamic proxy, first take a look at the usual dynamic proxy Demo we wrote, to throw a brick to attract stones
In general, defining a JDK dynamic proxy consists of three steps, as shown below
- Defining the proxy interface
- Define the proxy interface implementation class
- Define dynamic proxy invocation handlers
The three-step code is shown below, if you have played dynamic proxy, you can understand it
public interface Subject { // Define the proxy interface
String sayHello(a);
}
public class SubjectImpl implements Subject { // Define the proxy interface implementation class
@Override
public String sayHello(a) {
System.out.println(" Hello World");
return "success"; }}public class ProxyInvocationHandler implements InvocationHandler { // Define the dynamic proxy invocation handler
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("🧱 🧱 🧱 enters the proxy call handler");
returnmethod.invoke(target, args); }}Copy the code
Write a test program, run it and see how it works, again in three steps
- Create an implementation class for the proxied interface
- To create a dynamic proxy class, say three parameters
- Class loader
- An array of interfaces implemented by a proxy class
- Calling handler (calling the proxied class method, passing through it each time)
- Method 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 following output is printed * calling handler: 🧱 🧱 🧱 enters the proxy calling handler * Proxyed implementation class: Hello World */}}Copy the code
The Demo function is realized, and the general running process is also clear. The following analysis should be carried out for the realization of the principle
Analysis of dynamic proxy principle
From the point of view of principle, how does the dynamic proxy test program perform
The first step is straightforward, creating an implementation class for the Subject interface, which is our normal implementation
The second step is to create a dynamic proxy object for the proxied object. How do I prove that this is a dynamic proxy object? As is shown in
JDK dynamic Proxy object name is regular, all generated by Proxy class dynamic Proxy object prefix must be $Proxy, followed by the number is part of the name
If you want to check out the Proxy inner class ProxyClassFactory, you will find the answer
Back to the ProxyInvocationHandler, which internally holds a reference to a class implemented by the proxyInterface, the invoke method internally uses reflection to call a class method implemented by the proxyInterface
The generated dynamic Proxy class inherits the Proxy class and implements the Subject interface. The invoke method of ProxyInvocationHandler is actually invoked in the implementation method sayHello
Accidentally discovered why JDK dynamic proxies can’t proxy classes ^ ^
That is, when we call Subject#sayHello, the method call chain looks like this
Mybatis Mapper does not have the implementation class of the proxy interface. How to play this
Don’t know it doesn’t matter, know the estimate can not see this, look at mybatis source code is how to play
Mybatis version: 3.4 x
Mybatis source code implementation
I don’t know if you thought about it on the exam, Mapper, why doesn’t Mapper need an implementation class?
For example, the three-tier design used in our project is Controller to control request reception, Service to handle business, and Mapper to handle database interaction
Mapper layer is also known as the database mapping layer, responsible for the operation of the database, such as the query of data or add, delete and so on
Bold assumption, the project does not use Mybatis, need to write database interaction in Mapper implementation layer, will write some content?
Write some general JDBC operations such as:
// Load the Mysql driver
Class.forName(driveName);
// Get the connection
con = DriverManager.getConnection(url, user, pass);
/ / create the Statement
Statement state = con.createStatement();
// Build the SQL statement
String stuQuerySqlStr = "SELECT * FROM student";
// Execute SQL to return the resultResultSet result = state.executeQuery(stuQuerySqlStr); .Copy the code
If all the Mapper implementation layers in the project were to play this way, wouldn’t it be very hard to beat people…
So Mybatis combined with the pain point of the project, emerged at the historic moment, how to do it
- All the operations and JDBC interaction, the underlying JDK dynamic proxy encapsulation, users only need to customize Mapper and.xml files
- SQL statements are defined in.xml files or Mapper, and are assembled into Objects in Java by parsers at project startup
There are different parsers because Mybatis contains not only static statements but also dynamic SQL statements
This is why Mapper interfaces do not need implementation classes, because they are already wrapped by Mybatis through dynamic proxies. If each Mapper has an implementation class, it is bloated and useless. After this operation, the Mybatis framework used in the project is shown to us
Mybatis Mapper interface can implement dynamic proxy without implementing classes
It is almost impossible to introduce the Mybatis dynamic proxy process in a strict sequence without previouslyreferring to unintroduced terminology, so I try to make it easy to understand
No implementation class completes dynamic proxy
The core point is here. Pick up the notebook and sit on it
Let’s take a look at whether it’s possible for a normal dynamic proxy to rely on interfaces instead of implementing classes
public interface Subject {
String sayHello(a);
}
public class ProxyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("🧱 🧱 🧱 enters the proxy call handler");
return "success"; }}Copy the code
As you can see from the code, we are not implementing the interface Subject. How to implement 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 following output is printed * call handler: 🧱 🧱 🧱 enter the proxy call handler */}}Copy the code
As you can see, the parameters of the proxy. newProxyInstance method have been changed
Instead of getting the Class array of the interface implemented by the implementation Class, we put the interface itself in the Class array
What is the difference between a dynamic proxy class with and without an implemented interface
- It’s good to have an implementation interface
InvocationHandler#invoke
Method invocation, the invoke method invokes the proided object (SubjectImpl) method (sayHello) via reflection - No implementation interface is only a pair
InvocationHandler#invoke
Generate the call.So an interface implementation returns the value returned by the propied-object interface, whereas an unimplemented interface returns only the value returned by the Invoke method
The InvocationHandler#invoke method returns a success string and defines a string variable to return successfully
The answer to the first question has now emerged. Mapper has no implementation class. All JDBC calls and other operations are implemented in Mybatis InvocationHandler
Since the problem has been solved, it seems that it is not so difficult, but you are not curious about how to do the bottom layer of Mybatis?
Ask a question and then look at the source code with the question in mind
We Demo interface is fixed, Mybatis Mapper but not fixed, how to do?
So says Mybatis
See Mybatis bottom it how to achieve dynamic interface proxy, small partners only need to pay attention to the code at the tag can
Much like our Demo code, the core point is mapperInterface how does it assign a value
First, let’s talk about the specific logic in Mybatis agent factory to generate dynamic proxy classes
- Based on the namespace associated with.xml, pass
Class#forName
Return Class objects by reflection (not just.xml namespace) - Pass the resulting Class object (actually the interface object) to the Mybatis agent factory to generate the proxy object, namely the mapperInterface property
Mybatis uses the fully qualified name of the interface to generate a Class object with Class#forName
In order to facilitate our understanding, through Mybatis source code to provide an example of the test class. Assume there is an interface AutoConstructorMapper and the corresponding.xml as follows
Perform the first step to get the Class object based on the.xml namespace
- Firstly, the namespace attribute of mapper tag on.xml is obtained in the first step, and the fully qualified information of mapper interface is obtained
- Get Class objects based on mapper fully qualified information
- Add to the corresponding mapper container and wait for the dynamic proxy object to be generated
If a dynamic proxy object is generated at this point, the proxy factory newInstance method is as follows:
At this point, the first mentioned Proxy, Mybatis dynamic Proxy related questions have all answered
Abstract classes can be dynamically proxy JDK
Code before conclusion, no!
public abstract class AbstractProxy {
abstract void sayHello(a);
}
AbstractProxy proxyInterface = (AbstractProxy) Proxy
.newProxyInstance(
ProxyTest.class.getClassLoader(),
new Class[]{AbstractProxy.class},
new ProxyInvocationHandler());
proxyInterface.sayHello();
Copy the code
Of course, error reporting is inevitable, and the JDK cannot proxy classes
JDK dynamic Proxy generates the Proxy class in the process of the code, there is no interface verification
An abstract class is a class, and an abstract doesn’t make an interface (like me, who is still handsome even though I have gained 60 kg).
The next time an interviewer asks this question, be clear: No
“Said
Combined with Mybatis using JDK dynamic proxy related issues, expand the article about, here is a summary
Q: Can JDK dynamic proxies be used against class proxies?
Because JDK dynamic Proxy generates Proxy classes that inherit from Proxy classes, Java cannot Proxy classes because of multiple inheritance
Q: Can abstract classes be dynamically proxy with JDK?
No. An abstract Class is essentially a Class. When Proxy generates a Proxy Class, it verifies whether the incoming Class is an interface
Q: Mybatis Mapper interface has no implementation class, how to implement the dynamic proxy?
Mybatis will get the Mapper interface Class object via Class#forname and generate the corresponding dynamic proxy object. The core business processing will be processed at InvocationHandler#invoke
I hope you can learn something from this article. If you are confused about the content of this article, you can leave a message or add the author’s friend to communicate. Best wishes!
Wechat search [source interest circle], pay attention to the public number after reply 123 receive content covers GO, Netty, Seata, SpringCloud Alibaba, development specifications, interview treasure book, data structure and other learning materials!