spring

Posted on By xqw

随手记录一下《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三级缓存:
提前暴露的对象思想:在对象还没有初始化、没有填充属性时先把”单例工厂”暴露出来

  1. A doCreateBean()初始化,由于还未创建,从一级缓存查不到,此时只是一个半成品(提前暴露的对象),放入三级缓存singletonFactories;
  2. A发现自己需要B对象,但是三级缓存中未发现B,创建B的半成品,放入singletonFactories;
  3. B发现自己需要A对象,从一级缓存singletonObjects和二级缓存earlySingletonObjects中未发现A,但是在三级缓存singletonFactories中发现A,将A放入二级缓存earlySingletonObjects,同时从三级缓存删除;
  4. 将A注入到对象B中;
  5. B完成属性填充,执行初始化方法,将自己放入第一级缓存中(此时B是一个完整的对象);
  6. A得到对象B,将B注入到A中;
  7. A完成属性填充,初始化,并放入到一级缓存中。

Spring循环依赖三级缓存是否可以去掉第三级缓存?
如果去除第三级缓存,不放入三级缓存singletonFactories,直接调用getEarlyBeanReference,也能正常执行;

测试结果是可以的,并且从源码上分析可以得出两种方式性能是一样的,并不会影响到Sping启动速度。那为什么Sping不选择二级缓存方式,而是要额外加一层缓存?

如果要使用二级缓存解决循环依赖,意味着Bean在构造完后就创建代理对象,这样违背了Spring设计原则。Spring结合AOP跟Bean的生命周期,是在Bean创建完全之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。

@Async循环依赖保存原因