Jrebel 在重新加载 Mapper XML 文件时清除 Mybatis 拦截器
Jrebel clear Mybatis interceptors when reload Mapper XML files
我正在使用 Jrebel 6.3.0 为我的 Spring 引导 Web 应用程序热重载 Mybatis 的映射器 XML。并且我使用了Java配置来配置Mybatis。
@Configuration
@ConditionalOnClass({ PageInterceptor.class })
@EnableConfigurationProperties(MybatisPageProperties.class)
@AutoConfigureBefore(MybatisAutoConfiguration.class)
public class MyBatisPageAutoConfiguration implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(MyBatisPageAutoConfiguration.class);
@Autowired
private MybatisPageProperties properties;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanUtil.setApplicationContext(applicationContext);
}
/**
*
*
* @return
*/
@Bean
public PageInterceptor pageInterceptor() {
LOG.info("========PageInterceptor========");
PageInterceptor pageInterceptor = new PageInterceptor();
Properties p = new Properties();
p.setProperty("dialect", properties.getDialect());
p.setProperty("sqlIdRegex", properties.getSqlIdRegex());
pageInterceptor.setProperties(p);
return pageInterceptor;
}
我发现 Jrebel 在重新加载映射器 xml 文件时清除了拦截器。
org.zeroturnaround.jrebel.mybatis.SqlMapReloader
private void reconfigure() {
log.infoEcho("Reloading SQL maps");
this.conf.reinit(); // Clear loadedResources and interceptors
reloadedResources.set(Collections.synchronizedSet(new HashSet()));
enterReloading();
try {
if (this.confBuilder != null)
this.confBuilder.reinit();
reconfigureAdditionalMappings();
exitReloading();
reloadedResources.remove();
}
finally
{
exitReloading();
reloadedResources.remove();
}
}
.........
private void reconfigureAdditionalMappings() {
for (ResourceDesc rd : (ResourceDesc[])this.additionalMappings.toArray(new ResourceDesc[0])) {
reconfigureMapping(rd);
}
}
private void reconfigureMapping(ResourceDesc rd) {
org.apache.ibatis.session.Configuration c = (org.apache.ibatis.session.Configuration)this.conf;
try { // Only reload loadedResources from Mapper XML files.
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(ResourceUtil.asInputStream(rd.url), c, rd.path, c.getSqlFragments());
xmlMapperBuilder.parse();
}
catch (Exception e) {
if ((e.getCause() instanceof java.io.FileNotFoundException)) removeMappingForDeletedResource(rd); else {
throw new RuntimeException("Failed to parse mapping resource: '" + rd.url + "'", e);
}
} finally {
ErrorContext.instance().reset();
}
}
org.zeroturnaround.jrebel.mybatis.cbp.ConfigurationCBP
public class ConfigurationCBP
extends JavassistClassBytecodeProcessor
{
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass)
throws Exception
{
ctClass.addInterface(cp.get(JrConfiguration.class.getName()));
ctClass.addField(new CtField(cp.get(SqlMapReloader.class.getName()), "reloader", ctClass));
CtConstructor[] constructors = ctClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
CtConstructor constructor = constructors[i];
if (constructor.callsSuper()) {
constructor.insertAfter("reloader = new " + SqlMapReloader.class.getName() + "([=13=]);");
}
}
ctClass.addMethod(CtNewMethod.make("public " + SqlMapReloader.class
.getName() + " getReloader() {" + " return reloader;" + "}", ctClass));
ctClass.addMethod(CtNewMethod.make("public void reinit() { loadedResources.clear(); ((" + JrInterceptorChain.class
.getName() + ") interceptorChain).jrClear();" + "}", ctClass));
ctClass.getDeclaredMethod("isResourceLoaded").insertAfter("if (reloader.doReload()) { loadedResources.remove(); $_ = false;}");
}
}
有没有办法让 Jrebel 保留拦截器?
我的项目是 web app,我们不需要在 prod-env 中进行此更改,我们只是在 dev-env 中使用 jrebel,所以只需修改从源 jar 中获取的源文件,并将其放在 src/test/java,它会被构建到classes目录,并替换原来jar中的class。不要将其放入 src/main/java 文件夹。
org.apache.ibatis.builder.xml.XMLMapperBuilder
...
public class XMLMapperBuilder extends BaseBuilder {
private static List<Interceptor> interceptors = new ArrayList<Interceptor>(); // Added by yuanjinyong
...
public void parse() {
...
parsePendingStatements();
// Added by yuanjinyong
if (interceptors.size() == 0) {
interceptors.addAll(configuration.getInterceptors());
}
if (configuration.getInterceptors().size() == 0) {
for (Interceptor interceptor : interceptors) {
configuration.addInterceptor(interceptor);
}
}
}
...
}
我正在使用 Jrebel 6.3.0 为我的 Spring 引导 Web 应用程序热重载 Mybatis 的映射器 XML。并且我使用了Java配置来配置Mybatis。
@Configuration
@ConditionalOnClass({ PageInterceptor.class })
@EnableConfigurationProperties(MybatisPageProperties.class)
@AutoConfigureBefore(MybatisAutoConfiguration.class)
public class MyBatisPageAutoConfiguration implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(MyBatisPageAutoConfiguration.class);
@Autowired
private MybatisPageProperties properties;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanUtil.setApplicationContext(applicationContext);
}
/**
*
*
* @return
*/
@Bean
public PageInterceptor pageInterceptor() {
LOG.info("========PageInterceptor========");
PageInterceptor pageInterceptor = new PageInterceptor();
Properties p = new Properties();
p.setProperty("dialect", properties.getDialect());
p.setProperty("sqlIdRegex", properties.getSqlIdRegex());
pageInterceptor.setProperties(p);
return pageInterceptor;
}
我发现 Jrebel 在重新加载映射器 xml 文件时清除了拦截器。
org.zeroturnaround.jrebel.mybatis.SqlMapReloader
private void reconfigure() {
log.infoEcho("Reloading SQL maps");
this.conf.reinit(); // Clear loadedResources and interceptors
reloadedResources.set(Collections.synchronizedSet(new HashSet()));
enterReloading();
try {
if (this.confBuilder != null)
this.confBuilder.reinit();
reconfigureAdditionalMappings();
exitReloading();
reloadedResources.remove();
}
finally
{
exitReloading();
reloadedResources.remove();
}
}
.........
private void reconfigureAdditionalMappings() {
for (ResourceDesc rd : (ResourceDesc[])this.additionalMappings.toArray(new ResourceDesc[0])) {
reconfigureMapping(rd);
}
}
private void reconfigureMapping(ResourceDesc rd) {
org.apache.ibatis.session.Configuration c = (org.apache.ibatis.session.Configuration)this.conf;
try { // Only reload loadedResources from Mapper XML files.
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(ResourceUtil.asInputStream(rd.url), c, rd.path, c.getSqlFragments());
xmlMapperBuilder.parse();
}
catch (Exception e) {
if ((e.getCause() instanceof java.io.FileNotFoundException)) removeMappingForDeletedResource(rd); else {
throw new RuntimeException("Failed to parse mapping resource: '" + rd.url + "'", e);
}
} finally {
ErrorContext.instance().reset();
}
}
org.zeroturnaround.jrebel.mybatis.cbp.ConfigurationCBP
public class ConfigurationCBP
extends JavassistClassBytecodeProcessor
{
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass)
throws Exception
{
ctClass.addInterface(cp.get(JrConfiguration.class.getName()));
ctClass.addField(new CtField(cp.get(SqlMapReloader.class.getName()), "reloader", ctClass));
CtConstructor[] constructors = ctClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
CtConstructor constructor = constructors[i];
if (constructor.callsSuper()) {
constructor.insertAfter("reloader = new " + SqlMapReloader.class.getName() + "([=13=]);");
}
}
ctClass.addMethod(CtNewMethod.make("public " + SqlMapReloader.class
.getName() + " getReloader() {" + " return reloader;" + "}", ctClass));
ctClass.addMethod(CtNewMethod.make("public void reinit() { loadedResources.clear(); ((" + JrInterceptorChain.class
.getName() + ") interceptorChain).jrClear();" + "}", ctClass));
ctClass.getDeclaredMethod("isResourceLoaded").insertAfter("if (reloader.doReload()) { loadedResources.remove(); $_ = false;}");
}
}
有没有办法让 Jrebel 保留拦截器?
我的项目是 web app,我们不需要在 prod-env 中进行此更改,我们只是在 dev-env 中使用 jrebel,所以只需修改从源 jar 中获取的源文件,并将其放在 src/test/java,它会被构建到classes目录,并替换原来jar中的class。不要将其放入 src/main/java 文件夹。
org.apache.ibatis.builder.xml.XMLMapperBuilder
...
public class XMLMapperBuilder extends BaseBuilder {
private static List<Interceptor> interceptors = new ArrayList<Interceptor>(); // Added by yuanjinyong
...
public void parse() {
...
parsePendingStatements();
// Added by yuanjinyong
if (interceptors.size() == 0) {
interceptors.addAll(configuration.getInterceptors());
}
if (configuration.getInterceptors().size() == 0) {
for (Interceptor interceptor : interceptors) {
configuration.addInterceptor(interceptor);
}
}
}
...
}