Lottery lec10
lec10 主要实现的是一个路由中间件,用来选择对应的分库和分表。
下面主要介绍在阅读代码中遇到的基础知识点和业务相关内容。
@ConditionalOnMissingBean注解
它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。
@ConditionalOnMissingBean
真正意义在于它的扩展性,即当你封装一个组件时,你的组件有个默认的实现类,这时为默认的实现类bean上,添加@ConditionalOnMissingBean
;而在外部,开发人员根据业务定义自己的bean,这时它就有意义了,当在外部出现多个相同类型bean时,spring会为我们选择不带@ConditionalOnMissingBean注解的实现;也就是说@ConditionalOnMissingBean
是当没有个性化bean时,提供一个默认的bean,这才是它的意义!
Aspect注解
@Aspect:作用是把当前类标识为一个切面供容器读取
@Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: final增强,不管是抛出异常或者正常退出都会执行
由此引入一个新的知识点:
自定义注解实现AOP方式:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DBRouter {
String key() default "";
}
// 实现自定义注解
// Target表明注解作用于类型和方法上
// Retention表明在运行时起作用
// Documented方便文档生成工具来生成文档
Aop部分
@Aspect
public class DBRouterJoinPoint {
@Pointcut("@annotation(cn.bugstack.middleware.db.router.annotation.DBRouter)")
public void aopPoint() {
}
// 增强方法的Aop实现
@Around("aopPoint() && @annotation(dbRouter)")
public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable {
}
}
JointPoint使用
上面代码中的ProceedingJoinPoint继承自JointPoint。这个JointPoint的意思就是切入点,那我们需要获取到切入点的什么信息呢?
- 切入点的方法名字及其参数
- 切入点方法标注的注解对象(通过该对象可以获取注解信息)
- 切入点目标对象(可以通过反射获取对象的类名,属性和方法名)
注:有一点非常重要,Spring的AOP只能支持到方法级别的切入。换句话说,切入点只能是某个方法。
// 获取切入点所在的目标对象
Object obj = jointpoint.getTarget();
Class class1 = obj.getClass()
// 获取切入点方法的名字
String methodName = joinPoint.getSignature().getName()
// 获取切入点方法的参数
Object[] args = joinPoint.getArgs();
// 获取方法上的注解对象
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
{
xxxxx annoObj= method.getAnnotation(xxxxxx.class);
}
return null;
instanceof关键字
instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false
ps:
null用instanceof跟任何类型比较时都是false
左边的对象实例不能是基础数据类型
在继续项目过程中,使用了反射的技术从对象中获取某一种属性的值
下面再去细致学习一下反射的知识
反射
反射的概念:是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
获取字节码文件对象的三种方式
// 1. class.forName(全类名)
Class class1 = Class.forName("com.itheima.reflectdemo.Student");
// 2. 通过class属性
Class class2 = Student.class;
//因为class文件在硬盘中是唯一的,所以,当这个文件加载到内存之后产生的对象也是唯一的
System.out.println(class1 == class2); // true
// 3. 通过对象方式获取
Student stu = new Student();
Class class3 = stu.getClass();
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true
解释一下字节码文件和字节码文件对象这两个概念:
字节码文件是java程序编译后生成的.class文件,字节码文件对象是class文件加载到内存后,虚拟机自动创建出来的对象。这个对象里面至少包含了:构造方法,成员变量,成员方法。
反射就是获取字节码文件对象,这个对象在内存中是唯一存在的。
简单来说,就是可以通过class字节码对象,来创建对象、获取对象的私有属性值等操作,拥有了class字节码对象,就可以对类和对象任意进行操作
java移位运算符
<< : 左移运算符,num << 1,相当于num乘以2
>> : 右移运算符,num >> 1,相当于num除以2
>>> : 无符号右移,忽略符号位,空位都以0补齐
Mybatis拦截器
学习一个技术,首先应该去理解,其是用来解决什么问题?能够用来做什么?
在当前场景中,通过路由,可以得到dbIdx和tbIdx这两个分库分表的索引,那么如何将索引插入sql语句当中呢?
mybatis拦截器可以做的工作就是:SQL修改、分页操作、数据过滤、SQL执行时间性能监控
mybatis的核心部件有什么呢?
Configuration:初始化基础配置,比如Mybatis别名
SqlSessionFactory:SqlSession工厂
SqlSession:作为Mybatis工作的主要顶层API,表示和数据库交互的会话,完成必要的数据库增删改查功能
Executor:MyBatis的内部执行器,它负责调用StatementHandler操作数据库,并把结果集通过ResultSetHandler进行自动映射,另外,它还处理二级缓存的操作。
StatementHandler:MyBatis直接在数据库执行SQL脚本的对象。另外它也实现了MyBatis的一级缓存
ParameterHandler:负责将用户传递的参数转换成JDBC Statement所需要的参数。是MyBatis实现SQL入参设置的对象。
ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合。是MyBatis把ResultSet集合映射成POJO的接口对象。
TypeHandler:负责Java数据类型和JDBC数据类型之间的映射和转换。
MappedStatement:MappedStatement维护了一条<select|update|delete|insert>节点的封装。
SqlSource :负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回。
BoundSql:表示动态生成的SQL语句以及相应的参数信息。
mybatis执行过程
下面介绍mybatis拦截器:
先看一下下面的代码
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DynamicMybatisPlugin implements Interceptor {
}
在代码中,困惑我的地方就在于Intercepts注解和Signature注解
@Intercepts:标志该类是一个拦截器;
@Signature:标志拦截器需要拦截哪一个接口的哪一个方法
type:四种类型接口(Executor 拦截执行器方法、StatementHandler 拦截SQL语法构建处理、 ParmeterHandler 拦截参数处理、ResultSetHandler 拦截结果集处理)的某一个接口;
method:对应接口中的某一个方法名;
args:对应接口中某一个方法的参数(因为重载);
接口Interceptor有三个接口方法:
public class DynamicMybatisPlugin implements Interceptor {
// 进行拦截时要执行的方法
// Invocation有三个字段
// private final Object target;
// private final Method method;
// private final Object[] args;
@Override
public Object intercept(Invocation invocation) throws Throwable {
return null;
}
// 插件用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理,可 以决定是否要进行拦截进而决定要返回一个什么样的目标对象,官方提供了示例:return Plugin.wrap(target, this);,可以在这个方法中提前进行拦截对象类型判断,提高性能:
@Override
public Object plugin(Object target) {
return null;
}
// 设置一些拦截器需要用到的变量参数
@Override
public void setProperties(Properties properties) {
}
}
在项目中,代码中拦截了StatementHandler对象,这个接口方法如下:
prepare: 用于创建一个具体的 Statement 对象的实现类或者是 Statement 对象
parametersize: 用于初始化 Statement 对象以及对sql的占位符进行赋值
update: 用于通知 Statement 对象将 insert、update、delete 操作推送到数据库
query: 用于通知 Statement 对象将 select 操作推送数据库并返回对应的查询结果
由于分库分表操作需要将数据库id和表id,填入sql语句中,在更改sql语句过程中,使用了正则表达式(又是知识盲区,之前虽然知道正则表达式的作用,但没有实际使用过
标签:Lottery,final,lec10,对象,class,cnblog,注解,方法,public From: https://www.cnblogs.com/xyfhsy/p/17963941