MyBatis框架思想总结

1:Mybatis的原理

  mybatis的底层使用的是反射机制来实现的,需要了解mybatis的原理,首先需要弄清楚两个问题

   1:动态代理,什么是动态代理,以及反射机制,怎么使用反射,以及自定义注解。

   2:mybatis的接口为什么可以调用,接口为什么可以生成对象。

第一个问题:什么是动态代理:动态代理就是对原对象的一个加强,在不改变原对象的同时,增加原对象的功能和属性。要实现动态代理必须满足一个条件(代理对象必须实现一个接口),动态代理其实就是和目标对象实现相同的接口,然后将目标对象传入,实现目标对象的同时,动态生成代理对象。目前比较流行的两个代理工具,jdk的动态代理,以及cglib动态代理。


KindWomen kw = (KindWomen) Proxy.newProxyInstance(p.getClass().getClassLoader(), p.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                 method.invoke(p, null);
                 
                 return 1;
            }
        });

上述中的kw就是代理对象,代理的目标对象就是p,则增强了目标对象的功能,invoke方法就是执行目标对象,return返回的是目标对象方法执行的结果。反射就不过多介绍了,比较基础。

第二个问题自定义注解:什么是自定义注解,自定义注解就是接口,且这个接口实现了java.lang.annotation接口,但是这种写法编译器不允许,所以自定义注解需要固定的写法:

public @interface MyTest {
	int age() default -1 ;
	
	String name() default "xiaozhilei";
	
	int value();

}

@interface 这种格式,就会使Mytest自动的去继承java.lang.annotation接口,接口中定义如下

Documented:某一类型的注释被javadoc或者某种类似的工具进行文档化

Inherited:指示注释类型被自动继承

Retention:指示注释类型将会保留多久;其默认值为RetentionPolicy.CLASS(编译器将把注释记录在类文件中,但在运行时VM不需要保留注释。);它还可以取值为RetentionPolicy.SOURCE(编译器要丢弃的注释。)和RetentionPolicy.RUNTIME(编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。)。其中@Override和@SuppressWarnings是RetentionPolicy.SOURCE级别的;@Deprecated是RetentionPolicy.RUNTIME级别的

Target:指示注释类型适用的程序元素的种类;其ElementType的取值可以是ANNOTATION_TYPE(注释类型声明),CONSTRUCTOR(构造器声明),FIELD(属性声明),TYPE等;例如:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME):

注意自定义的注解可以用在,方法,属性,类上面,因为这些pojo都实现了java.lang.annotation接口,可以使用自定义注解,使用他的方法。

自定义注解需要会的几个方法:

public class MyUserHandler implements InvocationHandler {

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		

	              //判断该方法上面是否有注解
		         boolean flag = method.isAnnotationPresent(ExtSelsecct.class);
				//如果该方法上面有注解则获取方法里面的参数
				ExtSelsecct select = method.getDeclaredAnnotation(ExtSelsecct.class);
				//获取注解中的值
				//String userType = select.value();
				//System.out.println("注解中的值:" + userType);	
				if(select != null){
				String value = select.value();
				System.out.println(value);
				System.out.println(method.getName()+ "方法返回值"+ method.getReturnType());

				}
			
			
			Parameter[] params = method.getParameters();
			for (Parameter parameter : params) {
				System.out.println(parameter.getType().getName() +"vlaue" + parameter.getType());
			}
			
			//遍历参数
			for (int i =0;i<args.length;i++) {
				System.out.println("args" + args[i]);
				
			}
		
 		//在反射的方法前执行
		System.out.println("开始执行查询操作  select * from rd_user where user_id  = 1");
		return "uername:xiaozhilei; age:20;height 175cm";
	}

1:method.isAnnotationPresent(ExtSelsecct.class) 判断该方法上是否有注解。

2:ExtSelsecct select = method.getDeclaredAnnotation(ExtSelsecct.class);  得到该方法上面的注解对象。

通过这些操作就可以对注解进行操作了。

2:mybatis通过接口生成对象的过程

这个其实上面已经介绍过了,mybatis接口生成对象,其实不是真正的接口对象,而是通过代理类来实现生成的代理对象。类似这种设计的还有匿名对象也是可以做到的,废话不多说看代码。

1:生成接口对象代码:

public void selectUser(){
	
		UserMapper mapper= (UserMapper) Proxy.newProxyInstance(UserMapper.class.getClassLoader(),new Class[]{UserMapper.class}, new MyUserHandler());
	
	    mapper.selectUserByUserId("xiaozhilei");
	}

通过proxy动态代理生成userMapper的代理对象,转成userMapper进行赋值,myuserHander是具体实现,代码如下2

2:怎么实现查询,那就更简单了,直接实现InvocationHandler,通过invoke方法就可以操作接口方法,实现查询,其实就是曾强他的功能,只是目标对象是接口,所有功能交给代理对象来处理。

public class MyUserHandler implements InvocationHandler {

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
	            //判断该方法上面是否有注解
		        boolean flag = method.isAnnotationPresent(ExtSelsecct.class);
				//如果该方法上面有注解则获取方法里面的参数
				ExtSelsecct select = method.getDeclaredAnnotation(ExtSelsecct.class);
				//获取注解中的值
				//String userType = select.value();
				//System.out.println("注解中的值:" + userType);	
				if(select != null){
				String value = select.value();
				System.out.println(value);
				System.out.println(method.getName()+ "方法返回值"+ method.getReturnType());

				}
			
			
			Parameter[] params = method.getParameters();
			for (Parameter parameter : params) {
				System.out.println(parameter.getType().getName() +"vlaue" + parameter.getType());
			}
			
			//遍历参数
			for (int i =0;i<args.length;i++) {
				System.out.println("args" + args[i]);
				
			}
		
 		//在反射的方法前执行
		System.out.println("开始执行查询操作  select * from rd_user where user_id  = 1");
		return "uername:xiaozhilei; age:20;height 175cm";
	}

这样整个mybatis的整个执行过程就结束了。

最后:我这个只是mybatis源码实现的思路,具体的源码的实现比这个更要复杂更要完善,希望看了这个对源码有更好的理解,让我们一起去探索吧。

猜你喜欢

转载自blog.csdn.net/qq_27469747/article/details/89014362