spring-beanFactory三

前两篇简单介绍了XmlBeanFactory如何加载xml以及如何创建bean,这都是完全基于xml配置的,那么注解又是如何处理的呢?以@Component和@Resource为例简单说明。

1 XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring/spring-test.xml"));
2 //BeanFactory不会自动添加BeanPostProcessor,ApplicationContext会
3 CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor = new CommonAnnotationBeanPostProcessor();
4 commonAnnotationBeanPostProcessor.setBeanFactory(factory);
5 factory.addBeanPostProcessor(commonAnnotationBeanPostProcessor);
6 MyBean bean = (MyBean) factory.getBean("myBean");
7 System.out.println(bean.name());//my bean
1 @Component("myBean")
2 public class MyBean {
3     @Resource
4     private MyBean myBean;
5     private String name = "my bean";
6     public String name() {
7         return myBean.name;
8     }
9 }
 1 <beans
 2         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3         xmlns="http://www.springframework.org/schema/beans"
 4         xmlns:context="http://www.springframework.org/schema/context"
 5         xsi:schemaLocation="http://www.springframework.org/schema/beans
 6        http://www.springframework.org/schema/beans/spring-beans.xsd
 7        http://www.springframework.org/schema/context
 8        http://www.springframework.org/schema/context/spring-context.xsd">
 9     <context:component-scan base-package="com.zyong.spring.beanfactory" />
10 </beans>

之前有提到过,将xml解析成Document后就会注册bean definitions,注册bean definition的过程就是解析Document的过程,之前分析了parseDefaultElement是处理bean标签的主要方法,现在来看delegate.parseCustomElement方法,它会处理一些复杂标签,比如component-scan。

 1 //DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法,有删减
 2 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 3     NodeList nl = root.getChildNodes();
 4     for (int i = 0; i < nl.getLength(); i++) {
 5         Node node = nl.item(i);
 6         if (node instanceof Element) {
 7             Element ele = (Element) node;
 8             if (delegate.isDefaultNamespace(ele)) {
 9                 parseDefaultElement(ele, delegate);
10             }
11             else {
12                 delegate.parseCustomElement(ele);
13             }
14         }
15     }
16 }
 1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
 2     //得到namespace,这里对于context:component-scan就是http://www.springframework.org/schema/context
 3     String namespaceUri = getNamespaceURI(ele);
 4     //spring会预注册一些NamespaceHandler,此处就会得到ContextNamespaceHandler
 5     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
 6     if (handler == null) {
 7         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
 8         return null;
 9     }
10     //使用NamespaceHandler解析该DOM节点
11     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
12 }
 1 public class ContextNamespaceHandler extends NamespaceHandlerSupport {
 2     //init方法会在NamespaceHandler构造完成后回调
 3     @Override
 4     public void init() {
 5         registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
 6         registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
 7         registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
 8         //NamespaceHandlerSupport中持有BeanDefinitionParser,
 9         //handler.parse会调用findParserForElement(element, parserContext).parse(element, parserContext),
10         //即将parse任务委托给具体的BeanDefinitionParser,这里就是ComponentScanBeanDefinitionParser
11         registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
12         registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
13         registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
14         registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
15         registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
16     }
17 }
 1 //ComponentScanBeanDefinitionParser的parse方法,该方法与解析bean标签类似,最终都会产生bean definition并注册。
 2 public BeanDefinition parse(Element element, ParserContext parserContext) {
 3     //得到package信息
 4     String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
 5     //进一步分析package路径
 6     basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
 7     String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
 8             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
 9
10     // Actually scan for bean definitions and register them.
11     ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
12     //doScan会遍历package下的类,通过filters检查是否应该将类注册为bean,如果检查通过则注册该bean definition。
13     //filters就会包含AnnotationTypeFilter,其annotationType为org.springframework.stereotype.Component,如果被检查类有@Compenent注解则将其视为bean
14     Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
15
16     registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
17
18     return null;
19 }

至此就将使用注解声明的bean注册进beanFactory了(还未实例化),由于此时在bean中使用了注解@Resource进行注入,故与xml注入有所差异。
由下表可知,beanFactory不会自动注册BeanPostProcessor,而通过文档发现注解的注入其实就是通过BeanPostProcessor完成的,所以测试代码中才会显示添加CommonAnnotationBeanPostProcessor。

Feature BeanFactory ApplicationContext

Bean instantiation/wiring


Yes


Yes


Automatic BeanPostProcessor registration


No


Yes


Automatic BeanFactoryPostProcessor registration


No


Yes


Convenient MessageSource access (for i18n)


No


Yes


ApplicationEvent publication


No


Yes

CommonAnnotationBeanPostProcessor是一个InstantiationAwareBeanPostProcessor,这里我们只关注其postProcessPropertyValues方法。

 1 //CommonAnnotationBeanPostProcessor的postProcessPropertyValues方法
 2 public PropertyValues postProcessPropertyValues(
 3         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 4
 5     InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
 6     try {
 7         //注入,注入逻辑无非就是遍历可注入属性(字段、方法),进行反射调用。
 8         metadata.inject(bean, beanName, pvs);
 9     }
10     catch (Throwable ex) {
11         throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
12     }
13     return pvs;
14 }

附:

时间: 2024-10-04 08:12:46

spring-beanFactory三的相关文章

Spring BeanFactory源码学习

一.BeanFactory BeanFactory是Spring IOC容器的基础,是IOC容器的基础接口,所有的容器都是从它这里继承实现而来.BeanFactory提供了最基本的IOC容器的功能,即所有的容器至少需要实现的标准.BeanFactory体系结构是典型的工厂方法模式,即什么样的工厂生产什么样的产品.BeanFactory是最基本的抽象工厂,而其他的IOC容器只不过是具体的工厂,对应着各自的Bean定义方法.但同时,其他容器也针对具体场景不同,进行了扩充,提供具体的服务. 二.Bea

攻城狮在路上(贰) Spring(四)--- Spring BeanFactory简介

BeanFactory时Spring框架最核心的接口,它提供了高级IoC的配置机制,使管理不同类型的Java对象成为了可能.我们一般称BeanFactory为IoC容器.BeanFactory是Spring的基础设施,面向Spring本身. 一.BeanFactory的体系结构: 二.类图说明: ListableBeanFactory:定义了访问容器中Bean基本信息的方法,查看Bean的个数.获取某一类型Bean的配置名,看容器中是否包含某一Bean等方法. HierarchicalBeanF

Spring BeanFactory 中的类型推断

Spring BeanFactory 中的类型推断 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) Spring 容器中可以根据 beanName 查找其类型,其推断方式和 bean 的创建方式密切相关,并且 Spring 中有一个原则是尽可能的不要通过创建 bean 来获取其类型,除了 FactoryBean 只有通过创建对象调用其 getObjectType 方法,但也只是部分的创建该 FactoryBean(所谓

Spring BeanFactory 依赖注入

Spring BeanFactory 依赖注入 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一.autowire 五种注入方式测试 (1) 环境准备 public class Company { private Department department; private List<Employee> employees; public Company() { } public Company(Departmen

攻城狮在路上(贰) Spring(三)--- Spring 资源访问利器Resource接口

Spring为了更好的满足各种底层资源的访问需求.设计了一个Resource接口,提供了更强的访问底层资源的能力.Spring框架使用Resource装载各种资源,包括配置文件资源.国际化属性文件资源等.一.Resource接口的主要方法有: boolean exists():资源是否存在. boolean isOpen():资源是否打开. URL getURL():如果底层资源可以表示为URL,该方法返回对应的URL对象. File getFile():如果底层资源对应一个文件,该方法返回对应

征服 Redis + Jedis + Spring (三)—— 列表操作【转】

一开始以为Spring下操作哈希表,列表,真就是那么土.恍惚间发现“stringRedisTemplate.opsForList()”的强大,抓紧时间恶补下. 相关链接: 征服 Redis 征服 Redis + Jedis 征服 Redis + Jedis + Spring (一)—— 配置&常规操作(GET SET DEL) 征服 Redis + Jedis + Spring (二)—— 哈希表操作(HMGET HMSET) 征服 Redis + Jedis + Spring (三)—— 列表

spring ioc三种注入方式

spring ioc三种注入方式 IOC ,全称 (Inverse Of Control) ,中文意思为:控制反转 什么是控制反转? 控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术. 由容器控制程序之间的关系,而不是由代码直接控制 由于控制权由代码转向了容器,所以称为反转 接口注入 Setter 注入 构造器注入 三种依赖注入方式的比较 : 接口注入: 接口注入模式因为历史较为悠久,在很多容器中都已经得到应用.但由于其在灵活性.易用性上不如其他两种注入模式,因而在 IOC 的专题世界

Redis实战之征服 Redis + Jedis + Spring (三)

一开始以为Spring下操作哈希表,列表,真就是那么土.恍惚间发现“stringRedisTemplate.opsForList()”的强大,抓紧时间恶补下. 通过spring-data-redis完成LINDEX, LLEN, LPOP, LPUSH, LRANGE, LREM, LSET, LTRIM, RPOP, RPUSH命令.其实还有一些命令,当前版本不支持.不过,这些List的操作方法可以实现队列,堆栈的正常操作,足够用了. 相关链接: Redis实战 Redis实战之Redis +

bean创建过程、spring BeanFactory的实现、spring aware

Bean的创建过程: Spring beanFactory的工厂模式实现: 解析<bean>标签,存到一个Map<String, Object> beans中 People o = (People)factory.getBean("p"); 因为map存的是object类型,所以取出时需要强制类型转换 Bean的生命周期: spring aware的目的是为了让Bean获得spring容器的服务,bean继承applicationContextAware可以获得

spring第三篇

在昨天下午更新sprin第二篇中,叙述了将对象交给spring创建和管理,今天在spring第三篇中,主要写两个点一是spring的思想 二是spring中bean元素的属性配置. 1 spring思想 1.1 IOC(Inverse of  Control) :控制反转,将对象的创建权交给了 Spring. 1.2  DI :Dependency Injection 依赖注入.需要有IOC 的环境,Spring 创建这个类的过程中,Spring 将类的依赖的属性设置进去. 实现IOC 需要DI