一、替换依赖
下列是现有spring相关依赖:
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-framework-bom</artifactid>
<version>${spring-framework.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-dependencies</artifactid>
<version>2.5.15</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>druid-spring-boot-starter</artifactid>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupid>org.apache.shiro</groupid>
<artifactid>shiro-spring</artifactid>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupid>org.mybatis.spring.boot</groupid>
<artifactid>mybatis-spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-aop</artifactid>
</dependency>
<dependency>
<groupid>com.github.pagehelper</groupid>
<artifactid>pagehelper-spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-thymeleaf</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-validation</artifactid>
</dependency>
<dependency>
<groupid>javax.servlet</groupid>
<artifactid>javax.servlet-api</artifactid>
</dependency>
<dependency>
<groupid>org.quartz-scheduler</groupid>
<artifactid>quartz</artifactid>
</dependency>
将上述依赖替换为一下依赖:
<!-- 父模块 -->
<parent>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-framework</artifactid>
<version>1.0.1</version>
</parent>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-logback</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-datasource</artifactid>
<version>${loveqq.framework.version}</version>
<exclusions>
<exclusion>
<groupid>com.zaxxer</groupid>
<artifactid>HikariCP</artifactid>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>druid</artifactid>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-shiro</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-mybatis</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-tomcat</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-aop</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-pagehelper</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-thymeleaf</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-validator</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>com.kfyty</groupid>
<artifactid>loveqq-boot-starter-quartz</artifactid>
<version>${loveqq.framework.version}</version>
</dependency>
<dependency>
<groupid>jakarta.annotation</groupid>
<artifactid>jakarta.annotation-api</artifactid>
</dependency>
<dependency>
<groupid>jakarta.servlet</groupid>
<artifactid>jakarta.servlet-api</artifactid>
<scope>provided</scope>
</dependency>
2、修改替换类
org.springframework.web.servlet.config.annotation.EnableWebMvc -> com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc
org.springframework.boot.autoconfigure.SpringBootApplication -> com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication
org.springframework.boot.SpringApplication -> com.kfyty.loveqq.framework.boot.K
org.springframework.context.annotation.ComponentScan -> com.kfyty.loveqq.framework.core.autoconfig.annotation.ComponentScan
org.springframework.stereotype.Component -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Component
org.springframework.context.annotation.Configuration -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Configuration
org.springframework.context.annotation.Bean -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean
org.springframework.context.annotation.Lazy -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Lazy
org.springframework.beans.factory.FactoryBean -> com.kfyty.loveqq.framework.core.autoconfig.beans.FactoryBean
org.springframework.context.annotation.Primary -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Primary
org.springframework.beans.factory.annotation.Value -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Value
org.springframework.boot.context.properties.ConfigurationProperties -> com.kfyty.loveqq.framework.core.autoconfig.annotation.ConfigurationProperties
org.springframework.cloud.context.config.annotation.RefreshScope -> com.kfyty.loveqq.framework.core.autoconfig.annotation.RefreshScope
org.springframework.beans.factory.annotation.Autowired -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired
org.springframework.scheduling.annotation.Async -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Async
org.springframework.context.event.EventListener -> com.kfyty.loveqq.framework.core.autoconfig.annotation.EventListener
org.springframework.stereotype.Service -> com.kfyty.loveqq.framework.core.autoconfig.annotation.Service
org.springframework.stereotype.Controller -> com.kfyty.loveqq.framework.web.core.annotation.Controller
org.springframework.web.bind.annotation.RestController -> com.kfyty.loveqq.framework.web.core.annotation.RestController
org.springframework.web.bind.annotation.ControllerAdvice -> com.kfyty.loveqq.framework.web.core.annotation.ControllerAdvice
org.springframework.web.bind.annotation.ExceptionHandler -> com.kfyty.loveqq.framework.web.core.annotation.ExceptionHandler
org.springframework.web.bind.annotation.RequestMapping -> com.kfyty.loveqq.framework.web.core.annotation.RequestMapping
org.springframework.web.bind.annotation.RequestBody -> com.kfyty.loveqq.framework.web.core.annotation.bind.RequestBody
org.springframework.web.bind.annotation.PathVariable -> com.kfyty.loveqq.framework.web.core.annotation.bind.PathVariable
org.springframework.web.bind.annotation.RequestMapping -> com.kfyty.loveqq.framework.web.core.annotation.RequestMapping
org.springframework.web.servlet.HandlerInterceptor -> com.kfyty.loveqq.framework.web.mvc.servlet.interceptor.HandlerInterceptor
org.springframework.web.multipart.MultipartFile -> com.kfyty.loveqq.framework.web.core.multipart.MultipartFile
org.springframework.ui.Model -> com.kfyty.loveqq.framework.web.core.request.support.Model
org.springframework.boot.web.servlet.FilterRegistrationBean -> com.kfyty.loveqq.framework.web.mvc.servlet.filter.FilterRegistrationBean
org.mybatis.spring.annotation.MapperScan -> com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.annotation.MapperScan
org.apache.shiro.spring.web.ShiroFilterFactoryBean -> com.kfyty.loveqq.framework.boot.security.shiro.autoconfig.ShiroFilterFactoryBean
org.mybatis.spring.SqlSessionTemplate -> com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.support.ConcurrentSqlSession
上述类的修改,基本上只需要替换包名即可,仅有很少的自定义配置逻辑需要稍微修改一下即可
3、配置文件修改
spring.profiles.active=druid -> k.config.include=application-druid.yml,generator.yml
server.port=80 -> k.server.port=80
spring.datasource.** -> k.datasource.**
mybatis.typeAliasesPackage=com.ruoyi.**.domain -> mybatis.typeAliasesPackage=com.ruoyi.**.domain.**.*
mybatis.mapperLocations=classpath*:mapper/**/*Mapper.xml -> mybatis.mapperLocations=mapper/**/*Mapper.xml
mybatis.configLocation=classpath:mybatis/mybatis-config.xml -> mybatis.configLocation=mybatis/mybatis-config.xml
新增配置:template.thymeleaf.prefix=/templates/
新增配置:template.thymeleaf.suffix=.html
上述编写了主要配置变更,详细的可以查看配置属性类,也可以使用 yml 配置。另外 loveqq 框架配置文件不支持横线分隔符到驼峰的无必要转换。
4、运行 Main 方法即可。
5、loveqq 的前世今生
loveqq 前身是 kfyty-framework
而 kfyty-framework 前身是 kfyty-utils
而 kfyty-utils 前身是 mybatis-demo
是的,刚开始仅仅是因为某个需求,是一张超级大宽表,要编写一个展示页面,由于字段实在太多,并且不只一个大宽表,因此就编写了一款代码生成器来辅助。并且这款代码生成器应该支持 java 编程式模板生成。但是又不想引入mybatis这种相对重量级的框架,而直接使用jdbc又比较繁琐,所以又编写了简单的可以基于注解执行SQL的简易版 mybatis,这便是 mybatis-demo。
后来,闲来无事,又想实现简易版 springmvc,并嵌入嵌入式tomcat,以加深对 springmvc 的理解。此时对项目更名为了 kfyty-utils,作为自己的工具集。
再后来,闲来无事,又想实现简易版 spring 及 springboot,以加深对 spring 的理解。此后便一直深耕,有时间就加入新功能。有读者可能发现,loveqq 框架的类命名和 spring 的基本上完全一致,这是就是原因。
初期是以学习 spring 进行开发的,但是却并没有参考 spring 的实现,仅仅是把 spring 当做一个黑盒接口,根据 spring 的外在功能表现,使用自己的想法去实现功能,所以该框架,即不是模仿 spring,也不是 spring 的二开。
比如:BeanDefinition 接口,在最初的版本实现中,并没有 bean 定义的概念,并且不支持构造方法注入,不支持普通方法注入,bean 必须有一个无参构造器。这么实现的目的是,避免复杂的循环依赖,所以此时仅有一级 bean 容器缓存。并且是扫描规则很粗暴,是扫描到带 @Component 或 @Bean 的组件,直接实例化并放入容器。后来想为 @Bean 方法增加参数,也就是为普通方法增加注入功能,但此时发现,几乎很难实现。因为我不知道此时要注入的 bean 存不存在,特别是循环依赖的场景下。因此必须引入 bean 定义的概念,先扫描 bean 定义,然后再实例化 bean。
再比如:loveqq 框架的自动配置,不需要 AutoConfigureBefore/AutoConfigureAfter 之类的辅助注解。因为 loveqq 框架在校验有条件的 bean 定义时,不仅会校验本身的条件,还会去校验该 bean 所依赖的 bean 的条件。还引入了 bean 条件引用概念,即使某些 bean 定义还未加载,也可以找到该 bean 所依赖的 bean 的条件。因此无需关心 bean 加载顺序的问题。下面就是一个很好的例子:
@BootApplication
public class ConditionTest {
private boolean isOverride;
@Autowired(required = false)
private List<inter> cons;
@Bean
public BB bbOverride() {
this.isOverride = true;
return new BB();
}
@EventListener
public void onComplete(ContextRefreshedEvent event) {
Assert.isTrue(this.isOverride);
Assert.isTrue(this.cons.size() == 5);
}
public static void main(String[] args) {
SpringApplication.run(ConditionTest.class, args);
}
}
interface Inter {}
@Component
@ConditionalOnBean({CC.class, BB.class})
@ConditionalOnClass(name = "com.kfyty.condition.ConditionTest")
class AA implements Inter {}
@Component
@ConditionalOnMissingBean(BB.class)
class BB implements Inter {}
@Component
@ConditionalOnBean(BB.class)
class CC implements Inter {
@Bean
@ConditionalOnBean(AA.class)
public EE ee() {
return new EE();
}
}
class DD implements Inter {}
@Component
@ConditionalOnMissingBean(DD.class)
class DDF implements FactoryBean<dd> {
@Override
public Class<!--?--> getObjectType() {
return DD.class;
}
@Override
public DD getObject() {
return new DD();
}
}
class EE implements Inter {}
上述代码,首先 BB 是无条件直接定义的,所以 BB 一定存在; 而 CC 仅依赖 BB 存在,所以 CC 一定存在; 而 AA 仅依赖 BB、CC 的存在,以及主类的存在,因此 AA 一定存在; 而 EE 仅依赖 AA,因此 EE 一定存在; 而我们没有直接定义 DD,因此 DDF 一定存在,而 DDF 属于 FactoryBean,它生产了 DD,所以 DD 一定存在; 所以 AA、BB、CC、DD、EE 的条件都成立,cons.size() 应该是 5。 而上述代码在 spring 下无法通过测试,但是在 loveqq-framework 中是可以测试通过的。
后来不断完善,准备正式发布,就更名为了 kfyty-framework,并发布了 kfyty-framework 1.0.0 版本。
再后来,有读者建议取个正式一点的名字,因为正式更名为 loveqq-framework,并发布了 1.0.1 版本。
感谢阅读,感兴趣的可在 github/gitee 搜索 loveqq-framework。其中 ruoyi-for-loveqq,仅在 gitee 上。</dd></inter>