A little question
Are you curious? When using spring to integrate mybatis, we directly inject mapper into the service layer. Mapper is just an interface, but it can be used directly. Why can it be used directly? Spring cannot be directly injected into the interface. With this question, let's analyze it below.
Dynamic agent
As we know, mybatis is actually implemented through dynamic agent. This article is just a brief description, and the specific implementation of myabtis is not described. Let's take a look at the content of dynamic proxy first.
Define an interface first
public interface TestMapper { void testZ(); }
Define a proxy class
public class TestMapperProxy implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy is "+proxy.getClass()); System.out.println("method name is "+method.getName()); return null; } }
test method
@Test public void test(){ TestMapper testMapper=(TestMapper) Proxy.newProxyInstance(TestMapper.class.getClassLoader(), new Class[] { TestMapper.class }, new TestMapperProxy()); testMapper.testZ(); }
The output result is
proxy is class com.sun.proxy.$Proxy4 method name is testZ
Through the above code, we can use a proxy to call an interface that is not implemented. Spring integration mybatis is actually the same method. We just need to put this proxy object into the spring container. So, how?
FactoryBean
We know that spring has FactoryBean and BeanFactory, and there are many articles comparing the two on the Internet. Let me briefly say:
- BeanFactory is the factory pattern, which stores some of our objects.
- FactoryBean is a bean. spring helps to construct objects, but sometimes we need to redefine the construction process of these objects.
FactoryBean has two important methods: getObject() and getObjectType().
- The getObject() method will return an object, which will be managed by spring.
- getObjectType() returns a class type, which is the class type of the object returned by getObject().
Next, let's look at the code:
@Component public class TestMapperFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { return Proxy.newProxyInstance(TestMapper.class.getClassLoader(),new Class[] { TestMapper.class }, new TestMapperProxy()); } @Override public Class<?> getObjectType() { return TestMapper.class; } }
Through the above methods, we put the object of type TestMapper into the spring container, and we can inject this mapper into other classes. Isn't it very simple. Next, let's look at the whole test code:
@RestController @RequestMapping("/testProxy") public class TestProxyController { @Autowired TestMapper testMapper; @RequestMapping("/testMapper") public String testMapper(){ testMapper.testZ(); return "OK"; } }
Output results:
proxy is class com.sun.proxy.$Proxy78 method name is testZ
myabtis uses MapperFactoryBean and ClassPathMapperScanner. You can study it when you are free.
It's done. Isn't it easy.
We just want to use this curiosity to see and learn something. I hope you can criticize and correct the shortcomings of the article.