随手记录一下《spring揭秘》的内容,日后整理
IOC
几个重要的接口/类 两种容器:
- BeanFactory (基础容器)
- ApplicationContext (在BeanFactory基础上构建的较高级的容器)
BeanFactory和ApplicationContext继承关系:

- BeanDefinition
每一个Bean在容器中都会有一个BeanDefinition的实例与之相对应,该BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。
当客户端向BeanFactory请求相应对象的时候,BeanFactory会通过这些信息为客户端返回一个完备可用的对象实例。RootBeanDefinition和ChildBeanDefinition是BeanDefinition的两个主要实现类 - BeanDefinitionRegistry (接口定义抽象了Bean的注册逻辑)
- BeanDefinitionReader (读取xml至BeanDefinition)
BeanFactory、BeanDefinition、BeanDefinitionRegistry关系:

BeanFactory、BeanDefinition、BeanDefinitionRegistry注册例子:
public static void main(String[] args) {
// 首先构造一个DefaultListableBeanFactory作为BeanDefinitionRegistry
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
//交给bindViaCode方法进行具体的对象注册和相关依赖管理,然后通过bindViaCode返回的BeanFactory
BeanFactory container = (BeanFactory) bindViaCode(beanRegistry);
FXNewsProvider newsProvider = (FXNewsProvider) container.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaCode(BeanDefinitionRegistry registry) {
//首先针对相应的业务对象构造与其相对应的BeanDefinition
AbstractBeanDefinition newsProvider = new RootBeanDefinition(FXNewsProvider.class, true);
AbstractBeanDefinition newsListener = new RootBeanDefinition(DowJonesNewsListener.class, true);
AbstractBeanDefinition newsPersister = new RootBeanDefinition(DowJonesNewsPersister.class, true);
// 将bean定义注册到容器中
registry.registerBeanDefinition("djNewsProvider", newsProvider);
registry.registerBeanDefinition("djListener", newsListener);
registry.registerBeanDefinition("djPersister", newsPersister);
// 指定依赖关系
// 1. 可以通过构造方法注入方式
ConstructorArgumentValues argValues = new ConstructorArgumentValues();
argValues.addIndexedArgumentValue(0, newsListener);
argValues.addIndexedArgumentValue(1, newsPersister);
newsProvider.setConstructorArgumentValues(argValues);
// 2. 或者通过setter方法注入方式
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue(new PropertyValue("newsListener", newsListener));
propertyValues.addPropertyValue(new PropertyValue("newPersistener", newsPersister));
newsProvider.setPropertyValues(propertyValues);
// 绑定完成 以BeanFactory的形式返回已经注册并绑定了所有相关业务对象的BeanDefinitionRegistry实例
return (BeanFactory) registry;
}
spring事务
@Transactional(propagation = Propagation.REQUIRES_NEW) 事务传播行为 TransactionDefinition接口定义了7中传播行为 ```java public interface TransactionDefinition {
/** 有就加入,没有创建
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/
int PROPAGATION_REQUIRED = 0;
/** 有就加入,没有不创建,直接执行
* Support a current transaction; execute non-transactionally if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> For transaction managers with transaction synchronization,
* {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
* at all, as it defines a transaction scope that synchronization might apply to.
* As a consequence, the same resources (a JDBC {@code Connection}, a
* Hibernate {@code Session}, etc) will be shared for the entire specified
* scope. Note that the exact behavior depends on the actual synchronization
* configuration of the transaction manager!
* <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
* not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
* <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
* synchronization conflicts at runtime). If such nesting is unavoidable, make sure
* to configure your transaction manager appropriately (typically switching to
* "synchronization on actual transaction").
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
*/
int PROPAGATION_SUPPORTS = 1;
/** 必须有事务,但是自己本身不创建,若没有事务报错
* Support a current transaction; throw an exception if no current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
* scope will always be driven by the surrounding transaction.
*/
int PROPAGATION_MANDATORY = 2;
/** 开启一个同级的事务,之前的事务被挂起
* Create a new transaction, suspending the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_REQUIRES_NEW = 3;
/** 不在事务里执行,如果有事务了,挂起,执行自己且不走事物
* Do not support a current transaction; rather always execute non-transactionally.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
* will be suspended and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_NOT_SUPPORTED = 4;
/** 不能有事物,否则报错
* Do not support a current transaction; throw an exception if a current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NEVER} scope.
*/
int PROPAGATION_NEVER = 5;
/** 开启一个(嵌套)子级的事务,
* 与REQUIRES_NEW类似,不过创建嵌套事务后之前的事务不会被挂起
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} otherwise. There is no
* analogous feature in EJB.
* <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
* specific transaction managers. Out of the box, this only applies to the JDBC
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* when working on a JDBC 3.0 driver. Some JTA providers might support
* nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
int PROPAGATION_NESTED = 6; } ```
记忆
若有加入,没有:
├ 创建 (PROPAGATION_REQUIRED = 0 default)
├ 不创建 (PROPAGATION_SUPPORTS = 1)
├ 抛异常 (PROPAGATION_MANDATORY = 2)
没有创建,有:
├开启同级 且 之前挂起 (PROPAGATION_REQUIRES_NEW = 3)
├不在事务里运行 且 之前挂起 (PROPAGATION_NOT_SUPPORTED = 4)
├开启子级 且 之前不挂起 (PROPAGATION_NESTED = 6)
├抛异常 (PROPAGATION_NEVER = 5)
spring三级缓存
思路:哪三级?创建bean的流程?为什么要三级,二级够不够
Spring是如何利用”三级缓存”
Spring三级缓存:
提前暴露的对象思想:在对象还没有初始化、没有填充属性时先把”单例工厂”暴露出来
- A doCreateBean()初始化,由于还未创建,从一级缓存查不到,此时只是一个半成品(提前暴露的对象),放入三级缓存singletonFactories;
- A发现自己需要B对象,但是三级缓存中未发现B,创建B的半成品,放入singletonFactories;
- B发现自己需要A对象,从一级缓存singletonObjects和二级缓存earlySingletonObjects中未发现A,但是在三级缓存singletonFactories中发现A,将A放入二级缓存earlySingletonObjects,同时从三级缓存删除;
- 将A注入到对象B中;
- B完成属性填充,执行初始化方法,将自己放入第一级缓存中(此时B是一个完整的对象);
- A得到对象B,将B注入到A中;
- A完成属性填充,初始化,并放入到一级缓存中。
Spring循环依赖三级缓存是否可以去掉第三级缓存?
如果去除第三级缓存,不放入三级缓存singletonFactories,直接调用getEarlyBeanReference,也能正常执行;
测试结果是可以的,并且从源码上分析可以得出两种方式性能是一样的,并不会影响到Sping启动速度。那为什么Sping不选择二级缓存方式,而是要额外加一层缓存?
如果要使用二级缓存解决循环依赖,意味着Bean在构造完后就创建代理对象,这样违背了Spring设计原则。Spring结合AOP跟Bean的生命周期,是在Bean创建完全之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。