CRM项目问题使用总结

一:mybatis 分页插件原理你了解多少
mabatis会先执行PageHelper.startPage方法:方法内容为创建一个包含分页参数的page对象,page对象会存储pagesize,pagenum和order by的消息,
然后放在ThreadLocal本地线程中。
紧接着就会通过mybatis分页插件进行sql的分页查询
其实mybatis分页插件工具实际上就是实现了mybatis框架的Interceptor接口的一个拦截器PageInterceptor;
这个分页过滤器首先会判断你本地线程对象中有没有pagesize和order by 的列;
如果有就会在sql查询的时候拼接上 select count 查询数据数量和数据数量是否大于零,如果数据量大于零就会把数据量set到Page对象中;
但你的代码执行sql时就会从ThreadLocal本地线程中获取page对象,然后在sql查询时就会拼接上pagesize,pagenum和order by的消息;
最终查询出来的list集合会放到Page对象中,然后将Page对象返回给前端.

ThreadLocal中使用了强引用和弱引用(强引用只要不为null就不会被GC回收,弱引用只要GC发现就会被回收),ThreadLocal中有一个ThreadLocalMap内部类
这个内部类有一个Entry内部类 有个Entry属性继承extends WeakReference弱引用
这个ENTRYmap的key(ThreadLocal对象)使用的是弱引用,value使用的是强引用,这个MAP使用的是强引用,
所以当线程结束时需要使用remove()方法回收这个对象,否则长时间积累会造成内存泄露;

=============================================
二:你们项目中登录时验证码是采用的什么方式实现的
我们项目采用的是图片加数学运算实现验证的
首先我们会通过UUID工具类生成一个UUID,然后我们会定义一个字符串拼接UUID作为存入到redis 中作为验证码的key
然后我们通过第三方工具类生成一个数学运算的图片和计算结果作为Code,
然后我们将key +code 存入到redis中并设置过期时间;
然后会将验证码图片和UUID返回给前端.
=============================================
三.你们项目采用预加载了吗,采用了是怎么样实现的,你们对哪些数据进行了预加载
在spring项目中有一个类SpringApplicationRunListener会监听bean的生命周期,bean的生命周期有三个阶段
初始化容器(创建对象,执行构造方法,执行属性注入,执行bean的初始化)到使用bean和关闭容器销毁bean;预加载阶段发生在bean的初始化阶段
我们项目是通过spring的生命周期来实现预加载的,生命周期初始化有两方式第一种是采用@PostConstruct注解,第二种就是通过实现InitializingBean这个接口来实现初始化
我们项目是采用的第一种通过@PostConstruct注解来实现初始化,
在初始化过程种我们加载了数据的编码,字典数据,常量数据登一些数据放到了redis中进行预加载.

注:
1.Springboot 监听机制----生命周期----初始化加载一些数据
2.SpringApplicationRunListener ---完成环境的准备工作
3.ApplicationContextInitializer ---- bean 对象上下文 的创建 =====@PostConstruct
4.CommandLineRunner  --- bean 对象创建后,项目启动完成之前 (参数是string[])多个启动方法可以通过@Order规定启动顺序
4.ApplicationRunner  ----- bean 对象创建后,项目启动完成之前(参数是ApplicationArguments)多个启动方法可以通过@Order规定启动顺序

==============================================
四:你们项目采用的是安全框架
我们项目采用是springSecurity的安全框架,这个框架中有一个名叫AuthenticationManager的类,类中有一个authonticate()方法,单调用这个方法是就会通过springSecurity
的14个拦截器对我们的用户登录进行验证;
我们首先定义了一个用户登录对象名为LoginUser implements UserDetails;
在我们项目中用户登录时我们会通过前端传入的UUID到redis中去查询Code,如果正确我们就会进行authonticate((new UsernamePasswordAuthenticationToken(username, password))方法
我们需要从数据库中去查询用户的数据,这里我们项目重写了SpringSecurity的UserDetailsService 接口中的方法来实现我们从数据库中查询用户数据,当数据库查询验证成功时
我们会在 UserDetailsService 接口的实现类中给LoginUser授权并生成token返回给前端;
在SpringSecurity中有一个过滤器OncePerRequestFilter,我们通过JwtAuthenticationTokenFilter继承在这个过滤器中对用户是否登录进行判断和Token解析如果成功就会对Token进行刷新操作,每次使用时都会延长Token时间.
==================================================
五.线程和线程池区别
进程是操作系统分配资源的基本单位;
线程是操作系统调度的基本单位。
线程有三种创建方式:new thead,implements runnable ,callable  ---在项目中只要创建线程就一直创建,会导致内存泄漏
线程池:七种创建方式
Executors.newFixedThreadPool()             -------创建一个固定大小
Executors.newCachedThreadPool()            -----创建一个可缓存的,大小是接口和服务器能力
Executors.newSingleThreadExecutor()        ----创建单个线程
Executors.newScheduledThreadPool()        -----创建一个可以执行延迟任务的线程池
ThreadPoolExecutor()                     ------手动创建线程池,可自定义7相关参数
自定义线程池的七个参数:
1.核心线程:一旦被创建就不会被销毁
2.最大线程数:核心线程数加零时线程数
3.空闲时间(值)
4.空闲时间(单位):临时线程的销毁时间
5.阻塞列队:
ArrayBlockingQueue    一个由数组结构组成的有界阻塞队列
LinkedBlockingQueue    一个由链表结构组成的有界阻塞队列
SynchronousQueue    一个不存储元素的阻塞队列,即直接提交给线程,不保持它们
PriorityBlockingQueue    一个支持优先级排序的无界阻塞队列
DelayQueue    一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素
LinkedTransferQueue    一个由链表结构组成的无界阻塞队列。与 SynchronousQueue 类似,还含有非阻塞方法
LinkedBlockingDeque    一个由链表结构组成的双向阻塞队列
6.创建线程的方式:
ThreadFactory threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            // 创建线程池中的线程
            Thread thread = new Thread(r);
            // 设置线程名称
            thread.setName("线程-" + r.hashCode());
            // 设置线程优先级
            thread.setPriority(Thread.MAX_PRIORITY);
            // 设置线程类型(守护线程、用户线程), false-用户线程
            thread.setDaemon(false);
            return thread;
        }
    };
7.拒绝策略:
    AbortPolicy:为线程池默认的拒绝策略,该策略直接抛异常处理。
    DiscardPolicy:直接抛弃不处理。
    DiscardOldestPolicy:丢弃队列中最老的任务。
    CallerRunsPolicy:将任务分配给当前执行execute方法线程来处理。

[线程池中线程数小于corePoolSize时,新任务将创建一个新线程执行任务,不论此时线程池中存在空闲线程;
线程池中线程数达到corePoolSize时,新任务将被放入workQueue中,等待线程池中任务调度执行;
当workQueue已满,且maximumPoolSize>corePoolSize时,新任务会创建新线程执行任务;
当workQueue已满,且提交任务数超过maximumPoolSize,任务由RejectedExecutionHandler处理;
当线程池中线程数超过corePoolSize,且超过这部分的空闲时间达到keepAliveTime时,回收该线程;
如果设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize范围内的线程空闲时间达到keepAliveTime也将回收]

匿名内部类 =====new thread 开启一个异步线程
// 匿名内部类 --它是子线程  结论:子线程跑的永远没有主线程快
=================================================================
六.异步日志
定义一个延迟线程管理类AsyncManager;属性中创建一个异步操作任务调度线程池 ScheduledExecutorService
ScheduledExecutorService .schedule(TimerTask task, 延迟时间值, 延迟时间单位);执行延迟任务
创建一个TimerTask对象重写run()方法
========================================================================
七.静态,@Autowired , @postConstruct 加载时机----?策略模式自动分配
静态 变量 / 静态代码块 > @ Autowired > @postConstruct > 构造方法
通过@ConditionalOnProperty()注解判断这个属性是否在配置文件中注入,如果注入这加载这个Bean类
@ConditionalOnProperty(name = "rule.clue.import", havingValue = "rule")
通过不通的配置实现不同类的配置加载
==========================================================================
八.异步并发线程
通过 CompletableFuture.supplyAsync()方法将需要执行的任务放到方法中进行执行
CompletableFuture<Integer> todayCluesNum = CompletableFuture.supplyAsync(() -> reportMpper.getTodayCluesNum(today, username)
);
CompletableFuture<Integer> todayBusinessNum = CompletableFuture.supplyAsync(() -> reportMpper.getTodayBusinessNum(today, username)
);
CompletableFuture.allOf(
        todayCluesNum,
        todayBusinessNum
).join();
todayCluesNum.get()
todayBusinessNum.get()
===================================================================
九.项目层次 实体类 封装
展示到页面的采用VO
业务逻辑层使用DTO
数据访问层和业务员逻辑层之间使用BO
数据访问层使用POJO/DAO
=============================================
十. 使用aop 自定义注解的方式进行日志记录
自定义了一个@Log注解,然后通过AOP思想,定义这个添加了@log的方法为切入点,通过@AfterReturning,@AfterThrowing对业务的两结果都进行日志插入

@Pointcut("@annotation(com.huike.common.annotation.Log)") 自定义注解作为切点
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") 在方法执行之后执行日志插入操作
@AfterThrowing(value = "logPointCut()", throwing = "e")   当执行任务发生异常时,进行异常插入操作
@Log(title = "修改已读", businessType = BusinessType.UPDATE)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

20岁30年经验的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值