Spring学习笔记(1):Spring基础及Bean注册

278 阅读6分钟

Spring体系结构

1. spring为什么流行:
	a. spring专注于做两件事情 IOC( 控制反转) 和 AOP(面向切面)
	b. spring的原则是不重新造轮子,通过对现有的比较好的解决方案提供支持和接入。
	c. spring的扩展思想都是通过实现提供的接口,然后把这些接口注册到bean容器中,然后spring就会根据这些bean实现的接口去扩展某些spring的功能。例如我们经常使用的SpringContextUtils
2. Spting 7 大模块 
	a. Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性
	b. Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口
	c. Spring Web:它提供Web应用开发的支持
	d. Spring MVC:它针对Web应用中MVC思想的实现
	e. Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
	f. Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等等。
	g. Spring AOP:AOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现

Spring入门使用

1. 上下文
	a. ClassPathXmlApplicationContext 加载xml配置文件
	b. AnnotationConfigApplicationContext 加载注解配置类 手动使用的时候整个spring都是从这里开始(有空再研究tomcat启动war包的时候的启动点)

@Configuration

1. @ComponentScan 对指定路径下的文件进行注解配置扫描
	a. Value="包名"
	b. includeFilter={数组项1,数组项2},需要在同级别里同时设置useDefaultFilters=false
		i. 每一个数组项是@Filter(type=xxx,,classes={xxx,xxx})
			1) 当type=FilterType.CUSTOM,代表自定义类,该自定义类需要实现TypeFilter接口,可以在match方法中根据一些java逻辑去判断类要不要进行加载(见右图1)
	c. excludeFilter={数组项1,数组项2},需要设置useDefaultFilters=true
		i. 数组项同上
	d. useDefaultFilters:默认true为全集,false为空集,全集时exclude,空集时include
2. @Scope 指定bean为例与多例,默认单例
3. @Lazy 例子在cap4 懒加载在获取bean的时候才初始化(那标记在@Autowired注入呢?)

图1

类注册

1. @Bean 
	a. 默认id为方法名
2. @Component以及其扩展
	a. 默认id为完整包类名
3.  @Conditional条件注册bean,使用在@Bean的注解上,代表对该Bean进行一次判断
	a. 选择性地注入一些bean,例如区分linux和win平台
		i. Filter的type=CUSTOM应该也能做到同样的事情,但是控制的粒度不一样
	b. 使用方法@Conditional(实现Conditional接口的类.class)
	c. 使用-Dos.name=linux 可以把os.name=linux覆盖虚拟机的环境变量中
4. @Import 快速给容器导入一个组件(区别于@Bean和@Component)
	a. @Import({Xxx.class}) 加载一个类,可包括第三方类
		i. 那只能使用默认构造器?
		ii. 这么想不还是@Bean更好用吗
	b. 与@Bean的区别
		i. @Import导入的类的默认id是类全称,@Bena为方法名
	c. 当@Import中注册的类实现了ImportSelector接口时,这个接口返回的String[]里包含对应的类也会被当成bean注注册,数组的内容为需要注册的类的全类名。
	d. 当@Import中注册的类实现了ImportBeanDefinitonRegistrar接口:
		i. 可以在处理的时候,通过registry对象获取已经注册的bean,可以更加灵活地通过条件判断来注册bean,例如想要判断同时有猫跟狗的时候才注册老鼠bean。
		ii. 当判断好需要注册的时候,也是通过registry.registerBeanDefinition("bienID",RootBeanDefinition类型的封装类)主动放入到bean的容器中(Spring的IOC容器本质上就是一个map<String,RootBeanDefinition>),通过主动实例化再封装成RootBeanDefinition包装类,再给ImportBeanDefinitonRegistrar注册
5. FactoryBean 一个泛形接口,也可以灵活地控制任意一个类的创建过程
	a. 可以把java实例通过FactoryBean注入到容器中,实现以下方法
		i. getObject
		ii. getObjectType
		iii. isSingleton
	b. 实现这个接口以后,要把这个实现类也当作一个普通bean注册到容器中,当我们获取bean时,Spring会判断取出的bean是否为FactoryBean子类,若true则使用该BeanFactory的getObject(),构造一个类型为getObjectType的bean,并缓存且赶回该bean(关键方法:org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean)。换言之就是使用FactoryBean生成的Bean,替代了原来Factory的位置。这时候使用id获取bean后得到的就是与泛型一致的实例。
	c. 想要获取FactoryBean的实例本身,需要在beanID前面加上符号“&”
	d. 很重要的一个类,与aop和processor相关
6. FactoryBean 和 BeanFactory有什么区别(这个定义好像有点疑问)
	a. FactoryBean是一种注册机制,可以把Bean通过FactoryBean注入到容器中
	b. BeanFactory 从我们的容器中获取实例化后的Bean

关于最后的FactoryBean,其实Spring的源码中就有很多类似这样的注解来引导我们读懂spring,挺好的。

能力有限,如果我的笔记中有问题,请大佬不吝指出,加油!

最后上点源码

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance

/**
	 * Get the object for the given bean instance, either the bean
	 * instance itself or its created object in case of a FactoryBean.
	 * @param beanInstance the shared bean instance
	 * @param name name that may include factory dereference prefix
	 * @param beanName the canonical bean name
	 * @param mbd the merged bean definition
	 * @return the object to expose for the bean
	 */
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean

/**
	/**
	 * Obtain an object to expose from the given FactoryBean.
	 * @param factory the FactoryBean instance
	 * @param beanName the name of the bean
	 * @param shouldPostProcess whether the bean is subject to post-processing
	 * @return the object obtained from the FactoryBean
	 * @throws BeanCreationException if FactoryBean object creation failed
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}