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
@Overridepublic 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方法如下:
?
@Overridepublic 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容器注入BeanDefinitionregisterComponents(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创建元数据readerMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);//根据reader判断是否BeanDefinitionif (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@Componentpublic @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。
?
@Testpublic 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的ClassReaderclassReader = 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 {@Overridepublic AnnotationVisitor visitAnnotation(String desc, boolean visible) {//解析过程中如果有annotation就会调用到我这个具体访问者的方法了,下面的Field和method类似System.out.println("visitAnnotation:"+desc);return super.visitAnnotation(desc, visible);}@Overridepublic 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);}@Overridepublic 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);//创建readerClassReader 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