现在的位置: 首页 > 综合 > 正文

spring + groovy 很强大

2017年12月21日 ⁄ 综合 ⁄ 共 7041字 ⁄ 字号 评论关闭

groovy是一门基于JVM的动态语言,跟spring结合更显强大,废话不多说,直接上例子

1、定义java接口 Foo.java

package groovy;

public interface Foo {
	void execute();
}

2、定义Groovy实现类 FooImpl.groovy

package groovy

import groovy.Foo

class FooImpl implements Foo {
	
	void execute() {
		println("hello!");
	}
	
}

3、定义spring配置文件 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:gorm="http://grails.org/schema/gorm"
	xsi:schemaLocation="http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://grails.org/schema/gorm http://grails.org/schema/gorm/gorm.xsd">

	<lang:groovy refresh-check-delay="500" script-source="groovy/FooImpl.groovy"></lang:groovy>

</beans>

4、测试类 GroovyTest.java

package groovy;

import java.util.Scanner;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class GroovyTest {
	public static void main(String[] args) {
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		Foo foo = context.getBean(Foo.class);
		Scanner in = new Scanner(System.in);
		while (true) {
			System.out.println("输入任意键");
			in.next();
			foo.execute();
		}
		
	}
}

ok,运行测试


修改FooImpl.groovy

package groovy

import groovy.Foo

class FooImpl implements Foo {
	
	void execute() {
		println("hello world!");
	}
	
}

到控制台再次输入



测试成功,程序不用重启,即可看到修改后的结果,再也不用其他热加载的插件了。

但是这样感觉不太爽,要是有很多接口实现类的话,不是要写一大堆配置文件?

虽然可以copy,也可以自动生成,但是我觉得还是不够完美,想个办法解决掉,办法就是动态加载bean,编写一个初始化bean,下次直接用即可。

该bean需要实现ApplicationContextAware接口,该接口可以拿到ApplicationContext,也就是spring容器,有了这个,我们就可以自己加一些bean到这个容器当中了。

为了实现这个效果,我可是花了不少功夫,由于网上又没有这个资料,只能自己硬着头皮,看源代码,终于皇天不负有心人 被我实现了,拿来共享一下

1、首先需要顶一个一个类实现ApplicationContextAware接口  GroovyFactory.java

package groovy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class GroovyFactory implements ApplicationContextAware {

	@Override
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		// 只有这个对象才能注册bean到spring容器
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
		
		// 因为spring会自动将xml解析成BeanDefinition对象然后进行实例化,这里我们没有用xml,所以自己定义BeanDefinition
		// 这些信息跟spring配置文件的方式差不多,只不过有些东西lang:groovy标签帮我们完成了
		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setBeanClassName("org.springframework.scripting.groovy.GroovyScriptFactory");
		final String refreshCheckDelay = "org.springframework.scripting.support.ScriptFactoryPostProcessor.refreshCheckDelay";
		final String language = "org.springframework.scripting.support.ScriptFactoryPostProcessor.language";
		// 刷新时间
		bd.setAttribute(refreshCheckDelay, 500);
		// 语言脚本
		bd.setAttribute(language, "groovy");
		// 文件目录
		bd.getConstructorArgumentValues().addIndexedArgumentValue(0, "groovy/FooImpl.groovy");
		// 注册到spring容器
		beanFactory.registerBeanDefinition("Foo", bd);
	}
	
}

2、然后将这个bean配置到applicationContext.xml 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:gorm="http://grails.org/schema/gorm"
	xsi:schemaLocation="http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://grails.org/schema/gorm http://grails.org/schema/gorm/gorm.xsd">

	<!-- 
	<lang:groovy refresh-check-delay="500" script-source="groovy/FooImpl.groovy"></lang:groovy>
	 -->
	 
	<bean class="groovy.GroovyFactory"></bean> 
	
	<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>

</beans>

3、这个多出了一个bean配置,事实上,这个bean在我们采用第一种方法配置的时候,spring后自动创建这个bean,然后我们没有采用这个方式,所以只能手动配置

4、运行程序,应该更刚才的结果是一样的

写到这里,可能会有人说我是多此一举了,不急,只要把GroovyFactory稍微修改一下,让其接受一个参数,其作用就明显,其参数是一个目录名,得到此目录名后,我们的bean就可以去扫描这个目录下的所有groovy文件,然后将其动态添加到spring容器中,这样无论我们添加了多少groovy类,都不需要去修改配置了,继续...

修改GroovyFactory.java

package groovy;

import java.io.File;
import java.io.FileFilter;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class GroovyFactory implements ApplicationContextAware {

	private String directory;
	
	public String getDirectory() {
		return directory;
	}

	public void setDirectory(String directory) {
		this.directory = directory;
	}

	@Override
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		// 只有这个对象才能注册bean到spring容器
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
		
		// 因为spring会自动将xml解析成BeanDefinition对象然后进行实例化,这里我们没有用xml,所以自己定义BeanDefinition
		// 这些信息跟spring配置文件的方式差不多,只不过有些东西lang:groovy标签帮我们完成了
		final String refreshCheckDelay = "org.springframework.scripting.support.ScriptFactoryPostProcessor.refreshCheckDelay";
		final String language = "org.springframework.scripting.support.ScriptFactoryPostProcessor.language";
		
		String realDirectory = Thread.currentThread().getContextClassLoader().getResource(directory).getFile();
		File root = new File(Thread.currentThread().getContextClassLoader().getResource(".").getFile());
		
		File[] files = new File(realDirectory).listFiles(new FileFilter() {
			@Override
			public boolean accept(File pathname) {
				return pathname.getName().endsWith(".groovy") ? true : false;
			}
		});
		for (File file : files) {
			GenericBeanDefinition bd = new GenericBeanDefinition();
			bd.setBeanClassName("org.springframework.scripting.groovy.GroovyScriptFactory");
			// 刷新时间
			bd.setAttribute(refreshCheckDelay, 500);
			// 语言脚本
			bd.setAttribute(language, "groovy");
			// 文件目录
			bd.getConstructorArgumentValues().addIndexedArgumentValue(0, file.getPath().replace(root.getPath(), ""));
			// 注册到spring容器
			beanFactory.registerBeanDefinition(file.getName().replace(".groovy", ""), bd);
		}
		
	}
	
}

接着修改applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:gorm="http://grails.org/schema/gorm"
	xsi:schemaLocation="http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://grails.org/schema/gorm http://grails.org/schema/gorm/gorm.xsd">

	<!-- 
	<lang:groovy refresh-check-delay="500" script-source="groovy/FooImpl.groovy"></lang:groovy>
	 -->
	 
	<bean class="groovy.GroovyFactory">
		<property name="directory" value="groovy"/>
	</bean> 
	
	<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>

</beans>

运行程序,结果跟上面一样,不一样的就是GroovyFactory从加载单个类,变成扫描目录,更实用了。

项目结构如下:



项目文件就不贴了,有需要的留言吧,累死了


抱歉!评论已关闭.