Spring学习笔记(1):Spring基础及Bean注册
2020-03-04 本文已影响0人
小飞飞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,挺好的。
image
能力有限,如果我的笔记中有问题,请大佬不吝指出,加油!
最后上点源码
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;
}
}