springboot整合jfinal ActiveRecord

一直在网上搜索springboot整合jfinal ActiveRecord的相关分享,但搜索的结果总是比较繁杂或者冗余,所以在这里自己也分享下,只贴核心内容:

一:首先我整合的环境说一下:

01、标准maven项目

02、springboot1.5.1.RELEASE(别的版本应该也没啥问题)

03、jfinal 3.5

04、mysql5.7

贴一下核心的依赖(pom.xml):

<!-- springboot父依赖 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.1.RELEASE</version>
</parent>

<!-- jfinal -->
<dependencies>
    <dependency>
        <groupId>com.jfinal</groupId>
        <artifactId>jfinal</artifactId>
        <version>3.5</version>
    </dependency>
    
</dependencies>

二:贴一下核心代码:

package com.xxx.xxx;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.source.ClassPathSourceFactory;

@Configuration
public class ActiveRecordPluginConfig {
	
	// 以下三个信息在 src/mian/resources/application.properties配置的数据库连接信息
	@Value("${spring.datasource.druid.username}")
	private String username;
	
	@Value("${spring.datasource.druid.password}")
	private String password;
	
	@Value("${spring.datasource.druid.url}")
	private String url;	
	
	@Bean
	public ActiveRecordPlugin initActiveRecordPlugin() {
		
		DruidPlugin druidPlugin = new DruidPlugin(url, username, password);
		
		// 加强数据库安全
		WallFilter wallFilter = new WallFilter();
			
		wallFilter.setDbType("mysql");
		
		druidPlugin.addFilter(wallFilter);
		// 添加 StatFilter 才会有统计数据
		druidPlugin.addFilter(new StatFilter());	
		
		ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
		
		arp.setShowSql(true);
		 
                arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
                
                // sql文件路径在src/mian/resources/sql/all_sqls.sql
                arp.addSqlTemplate("/sql/all_sqls.sql");
        		
        //	arp.addMapping("blog", Blog.class);
        	    
        	// 与 jfinal web 环境唯一的不同是要手动调用一次相关插件的start()方法
                druidPlugin.start();
        	arp.start();
        		
        	return arp;
	}
		
}

三:一、二两步已经完成了整合,接下来有一个开发过程的小问题,简单描述一下

前提:用的spring-boot-devtools支持开发过程中的热加载

问题:开发的过程中如果您修改了代码,项目进行了热加载,自动启动,会报以下错误:

2019-01-23 14:34:38.511- [restartedMain]- [ERROR]- [o.s.boot.SpringApplication]- [Application startup failed]- 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initActiveRecordPlugin' defined in class path resource [com/gistone/config/ActiveRecordPluginConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.jfinal.plugin.activerecord.ActiveRecordPlugin]: Factory method 'initActiveRecordPlugin' threw exception; nested exception is java.lang.IllegalArgumentException: Config already exists: main
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151)
	at com.gistone.SpringBootSampleApplication.main(SpringBootSampleApplication.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.jfinal.plugin.activerecord.ActiveRecordPlugin]: Factory method 'initActiveRecordPlugin' threw exception; nested exception is java.lang.IllegalArgumentException: Config already exists: main
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
	... 23 common frames omitted
Caused by: java.lang.IllegalArgumentException: Config already exists: main
	at com.jfinal.plugin.activerecord.DbKit.addConfig(DbKit.java:63)
	at com.jfinal.plugin.activerecord.ActiveRecordPlugin.start(ActiveRecordPlugin.java:227)
	at com.gistone.config.ActiveRecordPluginConfig.initActiveRecordPlugin(ActiveRecordPluginConfig.java:47)
	at com.gistone.config.ActiveRecordPluginConfig$$EnhancerBySpringCGLIB$$ac4f4599.CGLIB$initActiveRecordPlugin$0(<generated>)
	at com.gistone.config.ActiveRecordPluginConfig$$EnhancerBySpringCGLIB$$ac4f4599$$FastClassBySpringCGLIB$$d1faec4e.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
	at com.gistone.config.ActiveRecordPluginConfig$$EnhancerBySpringCGLIB$$ac4f4599.initActiveRecordPlugin(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
	... 24 common frames omitted

愿因就是以下两行代码:

druidPlugin.start();
arp.start();

解决方案:

在src/main/resources/目录下创建文件夹META-INF,在该文件夹下创建文件spring-devtools.properties

内容如下,只有一行:

restart.include.thirdparty=/jfinal-3.5.jar

到这里就万事大吉了,that's all~

备注:具体底层的原因,一些细节我也不是很清楚,欢迎大牛补充,再附一下另一个分享地址,或许能对您起到帮助作用

https://www.jfinal.com/share/457

评论区

JFinal

2019-01-23 14:48

目前为止最全面最好的 spring 整合 jfinal active record 的分享了

通过下面的配置解决热加载是很关键的分享:
restart.include.thirdparty=/jfinal-3.5.jar

此外,有个小建议: setSourceFactory(new ClassPathSourceFactory()) 改成 :
setToClassPathSourceFactory()
可更省代码,也可以少引入一个类

谢谢分享

来自星星的猫教授

2019-01-23 15:40

直接用Jfinal就好了,为嘛还要整合?

happyboy

2019-01-23 15:50

@来自星星的猫教授 有很多老项目或者已经启动的项目。

快乐的蹦豆子

2019-01-23 16:26

用法贴一下,比如事务控制 依赖注入

walking_

2019-01-23 16:28

@快乐的蹦豆子 https://www.jfinal.com/doc/5-1

caoxusheng

2019-01-23 16:48

@快乐的蹦豆子 事物用spring aop实现,把jfinal 的Tx.class的实现拿过来就行了

快乐的蹦豆子

2019-01-24 16:25

@caoxusheng 嗯,木问题

wxcmyx

2019-01-31 10:00

之所以整合是为了更好的利用spring生态,包括集群部署,熔断机制,微服务网关,监控体系,日志体系等

wxcmyx

2019-01-31 10:16

https://github.com/wxcmyx/jfinal-springboot-demo/blob/master/src/main/java/com/wixct/demo/config/DataSourceConfig.java 整合springboot 2.1.1

wxcmyx

2019-02-08 16:06

热加载的问题来自DbKit.java的62-64行:
if (configNameToConfig.containsKey(config.getName())) {
throw new IllegalArgumentException("Config already exists: " + config.getName());
}
如果去掉这段代码就可以了,@JFinal 在新版本中是否可以去掉这段代码?

JFinal

2019-02-15 21:35

@wxcmyx 去掉这个会带来新的问题,加个类似这样的配置就可以了:
restart.include.thirdparty=/jfinal-3.6.jar