`

通过bean parser实现spring scan groovy文件装载bean

 
阅读更多

Spring使用groovy作为bean,官方用了lang标签,但都是一个个文件。Groovy本身编译成class文件后当然可以和Java完全一样可以被component-scan。

 

但是我想实现能够扫描groovy文件,并且groovy文件发生修改时候能够重新load(方便开发环境中提高效率),网上查查了,然后自己摸索了下,简单实现了。

 

思路:

1. 通过NamespaceHandlerSupport自己写一个parser,parser和已有的component-scan的区别就是修改了ClassPathBeanDefinitionScanner的reourceLoader,classloader用GroovyClassLoader,metadataReaderFactory重写了一个支持groovy class的,spring的是用asm去解析class文件(所以他也只支持编译后的)。

 

2. 写个timer监听groovy文件的最后修改时间,发生变化的,就让application context reload。

 

代码献上

 

import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ComponentScanBeanDefinitionParser;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.w3c.dom.Element;

public class ComponentGroovyScanParser extends ComponentScanBeanDefinitionParser {
	
	@Override
	protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
		ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), true);
		scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
		scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
		scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

		scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));

		scanner.setResourceLoader(new PathMatchingResourcePatternResolver(ClassLoaderHolder.gcl));
		scanner.setResourcePattern("**/*.groovy");
		PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(
				ClassLoaderHolder.gcl);
		scanner.setMetadataReaderFactory(new CachingMetadataReaderFactory2(resourcePatternResolver));

		return scanner;
	}
}

 

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.asm.Opcodes;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

public class CachingMetadataReaderFactory2 extends SimpleMetadataReaderFactory {

	/** Default maximum number of entries for the MetadataReader cache: 256 */
	public static final int DEFAULT_CACHE_LIMIT = 256;

	private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;

	@SuppressWarnings("serial")
	private final Map<Resource, MetadataReader> metadataReaderCache = new LinkedHashMap<Resource, MetadataReader>(
			DEFAULT_CACHE_LIMIT, 0.75f, true) {
		@Override
		protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
			return size() > getCacheLimit();
		}
	};

	/**
	 * Create a new CachingMetadataReaderFactory for the default class loader.
	 */
	public CachingMetadataReaderFactory2() {
		super();
	}

	/**
	 * Create a new CachingMetadataReaderFactory for the given resource loader.
	 * 
	 * @param resourceLoader
	 *            the Spring ResourceLoader to use (also determines the
	 *            ClassLoader to use)
	 */
	public CachingMetadataReaderFactory2(ResourceLoader resourceLoader) {
		super(resourceLoader);
	}

	/**
	 * Create a new CachingMetadataReaderFactory for the given class loader.
	 * 
	 * @param classLoader
	 *            the ClassLoader to use
	 */
	public CachingMetadataReaderFactory2(ClassLoader classLoader) {
		super(classLoader);
	}

	/**
	 * Specify the maximum number of entries for the MetadataReader cache.
	 * Default is 256.
	 */
	public void setCacheLimit(int cacheLimit) {
		this.cacheLimit = cacheLimit;
	}

	/**
	 * Return the maximum number of entries for the MetadataReader cache.
	 */
	public int getCacheLimit() {
		return this.cacheLimit;
	}

	@Override
	public MetadataReader getMetadataReader(Resource resource) throws IOException {
		if (getCacheLimit() <= 0) {
			return super.getMetadataReader(resource);
		}
		synchronized (this.metadataReaderCache) {
			MetadataReader metadataReader = this.metadataReaderCache.get(resource);
			if (metadataReader == null) {
				metadataReader = genReader(resource);
				this.metadataReaderCache.put(resource, metadataReader);
			}
			return metadataReader;
		}
	}

	@SuppressWarnings("rawtypes")
	private MetadataReader genReader(final Resource resource) throws IOException {
		Class clz = ClassLoaderHolder.gcl.parseClass(resource.getFile());

		final AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(
				super.getResourceLoader().getClassLoader());

		Class[] ll = clz.getInterfaces();
		// must has GroovyObject
		String[] interfaces = new String[ll.length];
		for (int i = 0; i < interfaces.length; i++) {
			interfaces[i] = ll[i].getName();
		}
		visitor.visit(0, Opcodes.ACC_PUBLIC, clz.getName(), null, clz.getSuperclass().getName(), interfaces);

		Annotation[] ll2 = clz.getAnnotations();
		if (ll2.length > 0) {
			for (Annotation ano : ll2) {
				visitor.getAnnotationTypes().add(ano.annotationType().getName());
			}
		}

		MetadataReader reader = new MetadataReader() {
			@Override
			public Resource getResource() {
				return resource;
			}

			@Override
			public ClassMetadata getClassMetadata() {
				return visitor;
			}

			@Override
			public AnnotationMetadata getAnnotationMetadata() {
				return visitor;
			}

		};
		return reader;
	}

	/**
	 * Clear the entire MetadataReader cache, removing all cached class
	 * metadata.
	 */
	public void clearCache() {
		synchronized (this.metadataReaderCache) {
			this.metadataReaderCache.clear();
		}
	}

}

 

import groovy.lang.GroovyClassLoader;

public class ClassLoaderHolder {
	public static GroovyClassLoader gcl = new GroovyClassLoader();

	static {
		gcl.addClasspath("src");
	}
}

 

0
6
分享到:
评论
1 楼 tongfan 2018-07-22  
有能跑起来的demo么??   按照你的思路 和代码 做的demo 在classLoad 找bean的时候一直找不到 ,classNotFund 应该是GroovyClassLoader 没有进入到spring 体系中。

相关推荐

    Groovy 动态修改XML

    1. **解析XML**:首先,使用XMLSlurper或XMLParser将XML字符串或文件转换为Groovy的DOM(文档对象模型)表示。例如: ```groovy def xml = new XmlSlurper().parseText('&lt;xml&gt;&lt;node&gt;text&lt;/node&gt;&lt;/xml&gt;') ``` 2. *...

    mp4parser实现视频切割拼接方法

    通过mp4parser,我们可以轻松地处理这些任务,实现灵活的视频处理功能。 总的来说,mp4parser是一个强大的工具,它使得开发者无需深入理解MP4文件的复杂结构,也能有效地进行视频处理。在处理大量视频内容时,掌握...

    MP4parser 对应的jar文件

    通过阅读项目的官方文档和示例代码,你可以快速掌握如何利用MP4parser来处理MP4文件。此外,由于这是一个开源项目,你可以根据需要自定义和扩展它的功能,以满足特定的项目需求。 总之,MP4parser是一个强大的工具...

    Spring 3.0所需jar文件和对应的配置文件

    nested exception is java.lang.IllegalStateException: Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are ...

    Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现.doc

    Spring AOP 是基于 IOC 的 Bean 加载来实现的,本文主要介绍 Spring AOP 原理解析的切面实现过程。AOP 切面的实现是将切面类的所有切面方法根据使用的注解生成对应 Advice,并将 Advice 连同切入点匹配器和切面类等...

    LogParser 2.2安装文件

    它提供了一种灵活的方式,通过SQL-like语法来查询和分析各种类型的文本日志文件,包括IIS日志、事件查看器日志、CSV文件等。下面将详细介绍LogParser 2.2的主要功能、特性以及安装过程。 **主要功能:** 1. **强大...

    SqlParser C++实现的SQL语法解释器

    总之,SqlParser C++实现的SQL语法解释器是一个强大的工具,它通过词法分析和语法分析解析SQL语句,为数据库操作提供了基础。理解和掌握SqlParser的工作原理,对于开发和维护与数据库相关的软件系统具有重要意义。

    XMLParser iphone

    XMLParser在iOS开发中是一种常用的解析XML数据的工具,它允许开发者将XML文件转换为可操作的数据结构,便于在iPhone应用程序中使用。XML(Extensible Markup Language)是一种标记语言,常用于存储和传输结构化数据...

    Spring Framework API文档

    Spring Framework API文档。...它实现了很优雅的MVC,对不同的数据访问技术提供了统一的接口,采用IOC使得可以很容易的实现bean的装配,提供了简洁的AOP并据此实现Transaction Management,等等......

    javaParser 包 javaparser-core-3.6.16.jar

    `javaparser-core-3.6.16.jar` 文件是 JavaParser 库的核心组件,包含了对 Java 语言解析所需的所有核心类和方法。 JavaParser 提供了对 Java 语法的深度理解,能够将源代码转换为抽象语法树(Abstract Syntax Tree...

    编译原理lex词法分析 parser generator vc++

    本主题聚焦于lex词法分析和parser generator的使用,结合VC++环境来实现编译器的构建。 **词法分析(Lex)** 词法分析,也称为扫描或Tokenizing,是编译器的第一个阶段。它的任务是将源代码分解成一系列的词素,...

    实现类似av_parser_parse2功能

    通过正确地分割和解析NAL单元,我们可以确保FFmpeg的解码器能够正确解码H264视频流,即使在文件指针不直接提供完整NAL单元的情况下。这个过程需要对FFmpeg的API有深入理解,并能灵活应对各种输入数据格式的挑战。

    spring源码注释中文

    Spring 框架是 Java 开发中的一个核心组件,它为构建可维护、模块化和松耦合的应用程序提供了一种强大的方式。...通过这些深入的学习,开发者可以更好地利用 Spring 框架来设计和实现高效、可扩展的 Java 应用程序。

    NLPIR-Parser.zip

    NLPIR-Parser作为NLPIR工具包的一部分,可能包含了用于解析和处理文本的接口、库文件、示例代码等资源。用户可以通过这些资源,快速集成NLPIR的功能到自己的应用中,实现对大数据内容的高效处理和分析。 总的来说,...

    apk-parser-2.6.9包文件.zip

    "apk-parser"就是一个强大的Java库,专用于解析APK文件,揭示其隐藏的元数据。本文将详细介绍apk-parser的使用方法和核心功能。 apk-parser是一个高效且全面的APK解析库,它的主要目标是帮助开发者和安全研究人员...

    视频编辑MP4 Parser代码与jar包

    MP4 Parser是一种强大的工具,专门用于处理和解析MP4格式的视频文件。MP4(MPEG-4 Part 14)是广泛应用于互联网上的多媒体容器格式,它能包含视频、音频、字幕、图像等多种媒体类型。在进行视频编辑时,理解并利用...

    table_parser类及测试文件

    值得注意的是,描述中提到了一个链接(http://blog.csdn.net/xiaodao1986/archive/2009/07/24/4378135.aspx),这可能提供了关于`table_parser`类更详细的实现和使用说明。在实际应用中,查看这个博客文章会帮助理解...

    spring-analysis

    Spring IOC(Inversion of Control)容器是一种设计模式,用于实现对对象创建和依赖关系管理的反转。通过这种方式,Spring容器负责创建对象,并将它们之间的依赖关系自动配置好,而不是由应用程序代码来完成这些工作。...

    spring-扩展点-namespacehandler(Spring自定义标签)

    通过实现`org.springframework.beans.factory.xml.NamespaceHandler`接口,我们可以定义自己的处理逻辑,将自定义标签转换为Spring能够理解的Bean定义。 `spring-web-namespacehandler`通常包含Spring MVC相关的...

    Xml配置文件解析包 xml parser

    提供对Xml文件的解析功能,xml, parser

Global site tag (gtag.js) - Google Analytics