`

spring4.0源码分析之注解━━━Annotation

 
阅读更多

       Annotation比起xml是各有优势,Annotation用起来就是简洁,少了大量的配置文件。配置文件则很容易的就看出类之间的关联,看xml配置文件即可。但是如果用Annotation,还得看java代码。至于选择使用什么就看自己实际的情况而定。这里讲解spring在用Annotation的时候,是怎么读取Annotation,又像IOC中注入BeanDefinition的。

       如果是用Annotation,则只需下面一行即可:

   

<!-- 激活spring的注解 ,有了下面一行,这行可以省略
		<context:annotation-config />
-->
<context:component-scan base-package="com.zzx.study" />

 

  • 怎么读取xml配置文件

    我们直接看spring-context-4.0.0.M2.jar文件下的META-INF目录下的spring.handlers文件有如下一行,至于怎么到这行,可看DefaultNamespaceHandlerResolver类的解析

  

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler

 

   即如果在xml配置文件中,如果命名空间为http://www.springframework.org/schema/context则使用org.springframework.context.config.ContextNamespaceHandler这个类来解析,ContextNamespaceHandler类有init,是初始化针对不同的标签用不同的类来解析。例如上面的component-scan,则使用ComponentScanBeanDefinitionParser类解析。具体怎么到这些类类解析xml,可参考另外一篇博文http://992012.iteye.com/blog/1921633

@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

       在ComponentScanBeanDefinitionParser类中使用到了ASM来获得Annotation,而不是使用java的反射。原因是java的反射效率相对ASM第三方字节码库来说低一点。所以使用到了ASM。如果想看ASM,可到这个官网上查看http://asm.ow2.org/。ComponentScanBeanDefinitionParser的parse方法如下:

 

@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// Actually scan for bean definitions and register them.
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//通过scanner找到符合要求的Annotation,通过ASM第三方库
		
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//向IOC容器注入BeanDefinition

		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

 

 

     在ClassPathBeanDefinitionScanner的doScan方法中,会调用到ClassPathScanningCandidateComponentProvider中的findCandidateComponents方法

     

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + "/" + this.resourcePattern;
			Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
//通过ASM创建元数据reader
						MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
//根据reader判断是否BeanDefinition			
			if (isCandidateComponent(metadataReader)) {
//这里创建了ScannedGenericBeanDefinition 
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

 

 

 

   如果是使用了Service,Repository同意是可以被spring认识到的,因为这两个类的类同样也有元数据@Component。

 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any
	 */
	String value() default "";

}

 

 

 

    这里顺带讲解一下ASM。

 

@Test
	public void test3() throws IOException{
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
		resolveBasePackage("com.zzx.study.spring") + "/" + "**/*.class";
		PathMatchingResourcePatternResolver  pathResolver = new PathMatchingResourcePatternResolver();
		Resource[] rr = pathResolver.getResources(packageSearchPath);
		for(Resource r:rr){
			if(r.getFilename().equals("UserDao.class")){
				System.out.println(r.getFilename());
				AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(Thread.currentThread().getContextClassLoader());
				InputStream is = new BufferedInputStream(r.getInputStream());
				
ClassReader classReader;
				try {
//创建ASM的ClassReader
					classReader = new ClassReader(is);
				}catch (IllegalArgumentException ex) {
					throw new NestedIOException("ASM ClassReader failed to parse class file - " +
							"probably due to a new Java class file version that isn't supported yet: " + r, ex);
				}
				finally {
					is.close();
				}
//调用reader的接受方法,这个方法实际就是解析class字节码的实现,这里使用了Visitor模式
				classReader.accept(visitor, ClassReader.SKIP_DEBUG);
				for(String annotationType:visitor.getAnnotationTypes()){
					System.out.println(annotationType);
				}
				System.out.println("hasAnnotation:"+visitor.hasAnnotation(Component.class.getName()));
				System.out.println("hasMetaAnnotation:"+visitor.hasMetaAnnotation(Component.class.getName()));
			}
			}
	}

 

 

  用户可以实现自己的visitor,也就是具体的访问者了。

 

 

public class MyOwnClassVisitor extends ClassVisitor {

	@Override
	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
		//解析过程中如果有annotation就会调用到我这个具体访问者的方法了,下面的Field和method类似
		System.out.println("visitAnnotation:"+desc);
		return super.visitAnnotation(desc, visible);
	}

	@Override
	public FieldVisitor visitField(int access, String name, String desc,
			String signature, Object value) {
		System.out.println("visitField:"+name);
		return super.visitField(access, name, desc, signature, value);
	}

	@Override
	public MethodVisitor visitMethod(int access, String name, String desc,
			String signature, String[] exceptions) {
		System.out.println("visitMethod:"+name);
		return super.visitMethod(access, name, desc, signature, exceptions);
	}

	public MyOwnClassVisitor(int api) {
		super(api);
	}

	public static void main(String[] args) throws IOException {
		MyOwnClassVisitor visitor = new MyOwnClassVisitor(
				SpringAsmInfo.ASM_VERSION);
		//创建reader
		ClassReader reader=new ClassReader("com.zzx.study.spring.dao.UserDao");
//		调用accept解析字节码,第一个参数传用户具体的访问者
		reader.accept(visitor, ClassReader.SKIP_DEBUG);
		System.out.println(reader.getSuperName());
	}
	

}

 

 
如果想了解visitor模式,可参考网上资料http://blog.csdn.net/chenjie19891104/article/details/6393770
分享到:
评论

相关推荐

    Spring对注解(Annotation)处理源码分析

    Spring对注解(Annotation)处理源码分析 解析和注入注解配置的资源 源码级别的分析

    spring的Annotation注解.

    ### Spring框架中的Annotation注解详解 #### 一、Spring与Annotation的基本概念 Spring框架通过引入Annotation,极大地简化了Java开发中的依赖注入(Dependency Injection, DI)和面向切面编程(AOP)的过程。...

    spring annotation注解

    Spring Annotation 注解 Spring 框架中的注解是用于在 Java 类中添加元数据的,通过这些元数据,Spring 框架可以在运行时提供更多的功能。 Spring 框架提供了多种类型的注解,例如 @Autowired、@Resource、@...

    spring4.0 Generic Qualifier(泛型限定).docx

    总的来说,Spring 4.0的泛型依赖注入是其众多改进之一,它提升了开发者的编码体验,使得依赖注入更加精确和安全。结合其他增强功能,如Java 8的支持和测试框架的改进,Spring 4.0为开发者提供了更强大、更灵活的工具...

    spring4.0 RestController.docx

    在Spring 4.0中,`@RestController`是一个重要的新特性,它标志着Spring MVC框架对RESTful服务支持的增强。`@RestController`是`@Controller`和`@ResponseBody`两个注解的组合,使得处理HTTP请求变得更加简洁和高效...

    学习Spring笔记_Annotation(注解)_Component

    7. **源码分析**:深入理解Spring注解的工作原理,需要查看其源码。通过阅读Spring的源码,可以了解到注解是如何被解析,如何与bean生命周期相结合,以及如何驱动Spring容器执行相应的操作。 8. **工具支持**:开发...

    Spring Annotation简介一

    1. **依赖注入(Dependency Injection, DI)**:Spring Annotation中最常用的注解之一是`@Autowired`,它实现了自动装配bean。当在类的字段或构造器上使用`@Autowired`时,Spring会自动寻找类型匹配的bean并注入。...

    spring4.0 API

    spring 4.0 未翻译java.lang.Object java.util.AbstractMap,V&gt; (implements java.util.Map,V&gt;) java.util.HashMap,V&gt; (implements java.lang.Cloneable, java.util.Map,V&gt;, java.io.Serializable) java.util....

    配置整合DWR3.0和Spring2.5使用annotation注解

    在本文中,我们将探讨如何将Direct Web Remoting (DWR) 3.0与Spring 2.5框架整合,并利用注解(Annotation)进行配置。DWR是一个允许JavaScript与Java服务器端进行交互的库,而Spring 2.5引入了对注解的强大支持,...

    spring4.0 Configuration的使用.docx

    ### Spring 4.0 中 @Configuration 的使用详解 #### 一、@Configuration ...通过以上介绍可以看出,在 Spring 4.0 中使用 **@Configuration** 注解提供了极其灵活且强大的配置方式,极大地提高了开发效率和可维护性。

    Spring demo 自动检测注解

    在Spring框架中,自动检测注解(Autowired)是核心特性之一,它极大地简化了依赖注入的过程,使得开发者能够更加专注于业务逻辑,而不是繁琐的配置。本文将深入探讨Spring中的自动检测注解及其工作原理。 首先,`@...

    spring中自定义注解(annotation)与AOP中获取注解

    在Spring框架中,自定义注解(Annotation)和AOP(面向切面编程)的结合使用,极大地增强了代码的可读性和可维护性。本文将深入探讨如何在Spring中创建自定义注解以及如何在AOP中有效地获取并利用这些注解。 首先,...

    Spring java注解,元注解和自定义注解

    自定义注解是Java和Spring中非常强大的功能之一。通过定义自定义注解,开发者可以为程序添加更多特定意义的信息,并通过Spring的AOP(面向切面编程)功能实现特定的行为。 1. **定义自定义注解** - 使用@interface...

    spring源码解析:元注解功能的实现.doc

    在Spring框架中,元注解(Meta-Annotation)是一种用于注解其他注解的特殊注解,它使得Spring能够提供更灵活的注解功能。元注解的使用始于Spring 2.5版本,目的是减少XML配置,提升开发效率。Spring Boot进一步推广...

    SSH2 annotation 实现struts2.1.6 spring2.5.6 hibernate3.3 全注解开发

    在这个特定的项目中,开发者选择了SSH2的特定版本:Struts2.1.6、Spring2.5.6和Hibernate3.3,并且强调了全注解开发,这意味着在配置文件中尽可能地使用注解来代替XML配置。 首先,让我们详细了解一下这三个框架的...

    Spring注释 注入方式源码示例,Annotation

    花了些时间做了一个实验,彻底弄懂了spring Annotation注入的方式。凡带有@Component,@Controller,@Service,@Repository 标志的等于告诉Spring这类将自动产生对象,而@Resource则等于XML配置中的ref,告诉spring此处...

    学习Spring笔记_Annotation(注解)_Autowired_Qualifier

    Spring的核心特性之一是使用注解来简化配置,其中`@Autowired`和`@Qualifier`是两个关键的注解,它们在自动装配Bean时发挥着重要作用。这篇学习Spring笔记将深入探讨这两个注解的用法、原理以及它们在实际开发中的...

    spring 的Annotation方式

    ### Spring的Annotation方式详解 #### 引言 随着Spring框架的发展,其依赖注入(DI)机制也经历了从XML配置向注解驱动的重大转变。自Spring 3.0版本起,框架引入了一系列注解来简化依赖配置,使得开发人员能够在不...

    Spring Annotation (注解)详解

    Spring注解是Spring框架中的一种核心特性,它允许开发者在Java源代码中嵌入元数据,简化了XML配置,提高了代码的可读性和维护性。从Spring 2.5开始,注解成为主流配置方式,提供了更加简洁和直观的Bean定义和依赖...

    Spring annotation

    Spring框架是Java开发中不可或缺的一部分,它通过提供丰富的注解简化了依赖注入、配置管理和AOP(面向切面编程)等任务。本文将深入探讨Spring注解及其在实际开发中的应用。 1. **依赖注入(Dependency Injection, ...

Global site tag (gtag.js) - Google Analytics