码迷,mamicode.com
首页 > 编程语言 > 详细

Spring源码解析-基于注解依赖注入

时间:2017-10-28 01:07:55      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:efault   throws   control   匹配   subclass   registry   font   ram   with   

在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置。

主要使用的是

AnnotationConfigApplicationContext: 一个注解配置上下文
AutowiredAnnotationBeanPostProcessor: spring提供的用于这一目的的BeanPostProcessor实现,用来检查当前对象是否有@Autowired标注的依赖注入。

项目中除了使用@Autowired之外,还可以选择JSR250的一些注解例如@Resource大致和@Autowired相同。
CommonAnnotationBeanPostProcessor:JSR250也需要BeanPostProcessor,spring实现类了。
在spring配置文件中添加<context:annotation-config/>可以将这些processor添加到spring容器中。
另外使用注解的方式还需要一个classpath-scanning功能,使用这一功能只需要在配置文件中添加<context:component-scan base-package=‘com.xx.xx‘>
@Component注解使用太宽泛,细分了@Controller,@Service等标注。

简单示例
@Component
public class AnnotationDemo {

    public void printInfo(){
        System.out.println(this.getClass());
    }
}

 

@Component
public class AnnotationDemo2 {

    public void printInfo(){
        System.out.println(this.getClass());
    }
}

测试类

@Test
    public void testAnnotationInject(){
       ApplicationContext context = new AnnotationConfigApplicationContext("org.lzyer.test");
       //指定某些类
        //ApplicationContext context = new AnnotationConfigApplicationContext(AnnotationDemo.class,AnnotationDemo2.class);
        AnnotationDemo ad = context.getBean(AnnotationDemo.class);
        AnnotationDemo2 ad2 = context.getBean(AnnotationDemo2.class);
        ad.printInfo();
        ad2.printInfo();
    }

方式一为加载包下带注解的类。方式二是指定某些类。

运行结果:

class org.lzyer.test.AnnotationDemo
class org.lzyer.test.AnnotationDemo2

注入流程

技术分享

    /**
     * Create a new AnnotationConfigApplicationContext, scanning for bean definitions
     * in the given packages and automatically refreshing the context.
     * @param basePackages the packages to check for annotated classes
     */
    public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);//扫描包
        refresh();//调用AbstractApplicationContext中的refresh方法
    }
/**
     * Perform a scan within the specified base packages.
     * @param basePackages the packages to check for annotated classes
     * @return number of beans registered
     */
    public int scan(String... basePackages) {
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

        doScan(basePackages);//扫描

        // Register annotation config processors, if necessary.
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

 

/**
     * Perform a scan within the specified base packages,
     * returning the registered bean definitions.
     * <p>This method does <i>not</i> register an annotation config processor
     * but rather leaves this up to the caller.
     * @param basePackages the packages to check for annotated classes
     * @return set of beans registered if any for tooling registration purposes (never {@code null})
     */
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        for (String basePackage : basePackages) {//遍历所有的包
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//查找候选组件
            for (BeanDefinition candidate : candidates) {
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);//注册beandefinition
                }
            }
        }
        return beanDefinitions;
    }

 

/**
     * Scan the class path for candidate components.
     * @param basePackage the package to check for annotated classes
     * @return a corresponding Set of autodetected bean definitions
     */
    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) {//遍历Resource
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {//通过asm获取class,暂且不研究asm
                        MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                        if (isCandidateComponent(metadataReader)) {//判断是否为候选组件
                            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;
    }

查看2个判断条件。

/**
     * Determine whether the given bean definition qualifies as candidate.
     * <p>The default implementation checks whether the class is concrete
     * (i.e. not abstract and not an interface). Can be overridden in subclasses.
     * @param beanDefinition the bean definition to check
     * @return whether the bean definition qualifies as a candidate component
     */
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
    }

进行匹配。

/**
     * Determine whether the given class does not match any exclude filter
     * and does match at least one include filter.
     * @param metadataReader the ASM ClassReader for the class
     * @return whether the class qualifies as a candidate component
     */
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

 

@Override
    protected boolean matchSelf(MetadataReader metadataReader) {
        AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
        return metadata.hasAnnotation(this.annotationType.getName()) ||
                (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
    }

查看hasAnnotation和 hasMetaAnnotation方法。

    @Override
    public boolean hasAnnotation(String annotationType) {
        return this.annotationSet.contains(annotationType);
    }

    @Override
    public boolean hasMetaAnnotation(String metaAnnotationType) {
        Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
        for (Set<String> metaTypes : allMetaTypes) {
            if (metaTypes.contains(metaAnnotationType)) {
                return true;
            }
        }
        return false;
    }
annotationSet包含的是注解,
metaAnnotationMap的key为注解,value是一个set。




Spring源码解析-基于注解依赖注入

标签:efault   throws   control   匹配   subclass   registry   font   ram   with   

原文地址:http://www.cnblogs.com/lzeffort/p/7745764.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!