【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();
}
}
}

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
网友评论