美文网首页
Spring注解处理器

Spring注解处理器

作者: lionel880 | 来源:发表于2018-01-31 11:11 被阅读0次

【Spring实战】Spring注解配置工作原理源码解析
http://blog.csdn.net/honghailiang888/article/details/74981445
先了解局部的技术细节,再了解总体流程的调用

技术细节

1.

如@Component,一般通过自动扫描方式配置
<context:component-scan base-package="com.mango.jtt"></context:component-scan>

找Spring的配置文件,相关的命名空间
http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
可能只到
http://www.springframework.org/schema/context=org.springframework.context

2

在开源代码中去找到相应代码,发现里面的defaultParse---- ComponentScanBeanDefinitionParser()进行分析
分析代码是如何进行扫描注解,如何注册到容器beanFactory

总体流程

总体流程重点是了解Spring容器的启动过程和bean的生命周期
Spring的核心是容器,容器有beanFactory和ApplicationContext,后者是更完善的,功能更齐备的容器
因此去分析org.springframework.context.support.AbstractApplicationContext.java,抽象类了解整体流程,看其中的refresg()方法

在bean初始化前,注解器等都已经扫描注册,因此扫描到bean有相应注解后,就可以用java反射,在bean生命周期的各个阶段,起作用

@Override  
    public void refresh() throws BeansException, IllegalStateException {  
        synchronized (this.startupShutdownMonitor) {  
            // Prepare this context for refreshing.  
            prepareRefresh();   //初始化前的准备,例如对系统属性或者环境变量进行准备及验证  
  
            // Tell the subclass to refresh the internal bean factory.  
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  //初始化BeanFactory,解析xml配置文件,其中标签<context:component-scan>就是在这里解析的  
  
            // Prepare the bean factory for use in this context.  
            prepareBeanFactory(beanFactory);  //配置工厂的标准上下文特征,例如上下文的类加载器和后处理器。  
  
            try {  
                // Allows post-processing of the bean factory in context subclasses.  
                postProcessBeanFactory(beanFactory);     //子类覆盖方法,做特殊处理,主要是后处理器相关  
  
                // Invoke factory processors registered as beans in the context.  
                invokeBeanFactoryPostProcessors(beanFactory);  //激活各种beanFactory处理器,实例化并调用所有注册的BeanFactoryPostProcessor bean,  
如果给定的话,尊重显式的顺序。注意这里和扫描时的bean处理器的区别。  
  
                // Register bean processors that intercept bean creation.  
                registerBeanPostProcessors(beanFactory);实例化并调用所有已注册的BeanPostProcessor bean,必须在应用程序bean的任何实例化之前调用它。这是本节的分析重点。这里就是实例化上面注册的bean处理器</span>  
  
                // Initialize message source for this context.  
                initMessageSource();    //初始化消息资源,国际化等用  
  
                // Initialize event multicaster for this context.  
                initApplicationEventMulticaster(); //初始化应用事件广播  
  
                // Initialize other special beans in specific context subclasses.  
                onRefresh();               //子类扩展  
  
                // Check for listener beans and register them.  
                registerListeners();   //注册监听器  
  
                // Instantiate all remaining (non-lazy-init) singletons.  
                finishBeanFactoryInitialization(beanFactory);   //实例化非延迟加载单例,包括所有注册非延迟加载bean的实例化  
  
                // Last step: publish corresponding event.  
                finishRefresh();     //完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人  
            }  
  
            catch (BeansException ex) {  
                if (logger.isWarnEnabled()) {  
                    logger.warn("Exception encountered during context initialization - " +  
                            "cancelling refresh attempt: " + ex);  
                }  
  
                // Destroy already created singletons to avoid dangling resources.  
                destroyBeans();  
  
                // Reset 'active' flag.  
                cancelRefresh(ex);  
  
                // Propagate exception to caller.  
                throw ex;  
            }  
  
            finally {  
                // Reset common introspection caches in Spring's core, since we  
                // might not ever need metadata for singleton beans anymore...  
                resetCommonCaches();  
            }  
        }  
    }  
无标题.jpg

1.利用asm技术扫描class文件,转化成Spring bean结构,把符合扫描规则的(主要是是否有相关的注解标注,例如@Component)bean注册到Spring 容器中beanFactory
2.注册处理器,包括注解处理器
3.实例化处理器(包括注解处理器),并将其注册到容器的beanPostProcessors列表中
4.创建bean的过程中个,属性注入或者初始化bean时会调用对应的注解处理器进行处理。

实战理解

以Spring-cache的@Cacheable为例进行实战理解
1.当spring启用spring-cache,首先在Spring-context的org.springframework.cache.config目录下,可以找到CacheNamespaceHander
这是XML命名空间的解析,
这个类干了什么,很简单,就是把2个Parser解析类注册到了Spring的 Map<String,BeanDefinitionParser>中

registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
registerBeanDefinitionParser("advice", new CacheAdviceParser());

先看
annotation-driven是干什么用的,这个这是选择时使用aspectJ模式,还是proxy模式的,节省篇幅不贴了

看CacheAdviceParser是干什么用的,可以看到,一个注解的实际功能逻辑在这里,doParser方法
具体的实现,可以看到通过doParser方法,BeanDefinitionBuilder填充了内容

class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {

    private static final String CACHEABLE_ELEMENT = "cacheable";

    private static final String CACHE_EVICT_ELEMENT = "cache-evict";

    private static final String CACHE_PUT_ELEMENT = "cache-put";

    private static final String METHOD_ATTRIBUTE = "method";

    private static final String DEFS_ELEMENT = "caching";


    @Override
    protected Class<?> getBeanClass(Element element) {
        return CacheInterceptor.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
        CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition());

        List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
        if (cacheDefs.size() >= 1) {
            // Using attributes source.
            List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
            builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
        }
        else {
            // Assume annotations source.
            builder.addPropertyValue("cacheOperationSources",
                    new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource"));
        }
    }
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
        Props prop = new Props(definition);
        // add cacheable first

        ManagedMap<TypedStringValue, Collection<CacheOperation>> cacheOpMap = new ManagedMap<TypedStringValue, Collection<CacheOperation>>();
        cacheOpMap.setSource(parserContext.extractSource(definition));

        List<Element> cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
  //  所有的@cacheable的方法              
  for (Element opElement : cacheableCacheMethods) {
            String name = prop.merge(opElement, parserContext.getReaderContext());
            TypedStringValue nameHolder = new TypedStringValue(name);
            nameHolder.setSource(parserContext.extractSource(opElement));
//build包含了cache所需的相关信息
            CacheableOperation.Builder builder = prop.merge(opElement,
                    parserContext.getReaderContext(), new CacheableOperation.Builder());
            builder.setUnless(getAttributeValue(opElement, "unless", ""));
            builder.setSync(Boolean.valueOf(getAttributeValue(opElement, "sync", "false")));

            Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
            if (col == null) {
                col = new ArrayList<CacheOperation>(2);
                cacheOpMap.put(nameHolder, col);
            }
            col.add(builder.build());
        }
...

至此我们得到了一个BeanDefinitionBuilder,那么这个是干嘛用的?
感觉Spring确实是 越来越大,复杂起来了,其实那么多实现对于学习没什么用处,感觉以后学习要去找比较基础的版本,便于理解,看看默认实现就行了
以下是网上找的代码,有利于理解
可以看到,构造出一个BeanDefinitionBuilder后,就可以注册到beanFactory中,从而当通过beanFactory动态创建bean,拿@cacheable的proxy实现就是通过代理类实现的

BeanDefinitionBuilder userBeanDefinitionBuilder = BeanDefinitionBuilder
                .genericBeanDefinition(User.class);
        userBeanDefinitionBuilder.addPropertyValue("username", "chinfeng");
        userBeanDefinitionBuilder.addPropertyValue("password", "123456");
        beanFactory.registerBeanDefinition("user",
                userBeanDefinitionBuilder.getRawBeanDefinition());
 
        BeanDefinitionBuilder usersBeanDefinitionBuilder = BeanDefinitionBuilder
                .genericBeanDefinition(UserService.class);
        usersBeanDefinitionBuilder.addPropertyReference("user", "user");
        beanFactory.registerBeanDefinition("userService",
                usersBeanDefinitionBuilder.getRawBeanDefinition());

感觉引申越来越广了,又查阅了一下Spring动态创建的过程,动态创建时通过实现 BeanDefinitionRegistryPostProcaessor实现的,(自行复兴Spring 生命周期)
Procaessor判断有符合注解的bean采用自定义的beanFacory创建既可以了,当然也可以在判断调用某个方法的时候动态代理

感觉快要结束了
查看Interceptor目录中的CacheProxyFactoryBean,可以看到在这里根据切点设置了Interceptor

相关文章

网友评论

      本文标题:Spring注解处理器

      本文链接:https://www.haomeiwen.com/subject/jmpczxtx.html