Spring入门:延迟初始化+预先初始化深入浅出

//对beans的配置多了一个default-lazy-init="true"
//问个问题:如果beans的default-lazy-init="true"执行之后会怎样?
//会影响到谁?会怎样影响它们?
<beans xmlns="" xmlns:xsi="" xsi:schemaLocation=""
       default-lazy-init="true">
    //该bean标签被执行之后会怎样?
    //调用CAAccountServiceImpl类的无参构造方法
    //构造出一个实例accountService
    //然后调用类中accountDao属性的setter方法给该属性赋值(也就是使实例完备)
    //但由于accountDao是一个自定义类的属性,很特别
    //那就只能去到对应的类中构造出一个实例出来
    //然后再赋值过去
    //不是一直好奇写好的bean类如何实例化的,如何调用方法的么?
    //答案就在这里
    //就是不直接操作,直接操作就搞死了嘛//间接才更加高级
    //ref一般表示对id值的引用
    //而这里ref有特别的含义:要赋值给属性的那个实例
    //这里的name表示:被赋值的那个属性
    //这里究竟发生了什么?
    //我有两个类
    //在其中一个类中,我要把另外一个类的实例作为本类中的一个属性
    //使其大致就是这样
    //问题是我为什么这样做呢???
    //这里我可以实例化出很多的实例
    //我还可以把这些实例放在容器中
    <bean id="accountService" class="com.wiley.beginningspring.ch2.~CAAccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
     
    //这里对bean的配置多了一个lazy-init="false"
    //该标签执行后,将调用类AccountDaoInMemoryImpl的无参构造函数
    //构造出一个实例accountDao
    //这里肯定存在一个顺序:
    //我是先实例accountService呢?还是先实例accountDao呢
    //傻子也看的出来,应该先实例出accountDao,然后再实例accountService
    //因为这样调用setter方法时候,才显得入情入理!!
    //确定必须是这种顺序之后,我怎么保证这种顺序呢?
    //lazy表示懒,懒的人总是磨磨蹭蹭到后面才来的
    //lazy表示的不是懒,而是作为懒的表现的先与后
    //所以这里多了个lazy-init="false":表面意思=不后初始化=先初始化
    //作为一个被依赖项我们更希望预先就创建出来!!!
    //所以这里多了个lazy-init="false"
    //那为什么要设置default-lazy-init="true"呢?
    //它是设置给beans的,这意味着,将会管理到下面的所有的bean
    //defalut表示默认
    //所以default-lazy-init="true"表示,默认就是后初始化(取值true/false的特性连起来才有更强的语义)
    //设置了这个反而就麻烦了
    //意味着我们必须在这里设置这个lazy-init="false"
    //注意!注意!通常情况下,我们什么都没设置,就说明:不设置的情况下:default-lazy-init="false"
    //这种情况下,意味着这里的不设置的情形就等同于lazy-init="false"的情形
    //众所周知的东西,直接默认吧,别废话了,废话多了就外行了
    <bean id="accountDao" class="com.wiley.beginningspring.ch2.~CAAccountDaoInMemoryImpl"
          lazy-init="false">
    </bean>
</beans>

该xml文件执行之后会怎样?
比如<bean>标签执行后会怎样?

理解初始化所必须知道的知识:

1 创建bean可以通过XML,当然也可以通过java(还是XML方便啊)

2 我们肯定最好把这些bean都先初始化出来,这样一来可以及早发现错误,但却消耗内存!(这一做法的学名叫预先初始化)

3 如果内存消耗真的很大,我们就换一种做法,不要先都初始化出来,到需要它的时候才初始化它(这一做法的学名叫延迟初始化)

4 beans中的default-lazy-init="true"实际上是将容器中的所有的bean的初始化创建都延迟了

5 bean中的lazy-init="false"实际上是对某个单独bean进行的设置,表示允许这个bean可以预先创建

4和5的做法其实就是,把所有人都关进黑监狱了,但是要允许每个犯人可以打开一扇窗户!!

上面是通过xml配置文件做到的延迟初始化!

我们可以换一种方式来做: 通过注解!!

这里必须要了解的知识:
1 首先,我做这样一件事:在applicationContext.xml文件中加一行代码:
  <context:component-scan base-package="com.ect.somepackage"/> 
  这一行执行后会发生什么?
  将自动扫描路径(base-package)下面的包(com.ect.somepackage),
  如果
  该包中的一个类带了@Service注解,
  将该类的Bean自动注册到Spring容器,
  这一做法等同于
  在applicationContext.xml文件定义<bean>,
  
  注解无非就是同一件事情另一种方式
  xml中定义标签方式和这种方式做的完全是同一件事情
  干同一件事情的两种方式的这种关系可以像下面这样理解:
  方式一等同于方式二
  把两种方式放在一起比较,就会更加清楚,这是一种很好的做法:
  @Service("xxxDao")
  //该注解做了什么呢?
  1调用 xxxDaoImpl类的无参构造方法
  2将该实例取名为xxxDao
  3注入到spring容器中
  4该实例称为bean
  @Scope("prototype")
  public class xxxDaoImpl implements xxxDao{
    .....  
  }
  
  相当于:
  <bean id="xxxDao"
        class="com.ect.somepackage.dao.xxxDaoImpl" scope="prototype">
         ......    
  </bean>   
  这个标签做的事情是:
  1.调用类xxxDaoImpl无参构造方法
  2.实例化xxxDaoImpl类,
  3.将实例取名为xxxDao,这个实例注入到spring容器中,成为Bean


代码一:

@Service("accountService")
//这个service做了什么事情呢?
//注解的类是谁?AccountServiceImpl!
//所以做的事情就是:实例化该类获得一个实例,取名为accountService,注册到spring容器称为bean
@Lazy(true)
//先忽略注解,先了解这个类
//定义的类是AccountServiceImpl 
//该类是一个实现的类
//实现的类是AccountService
//这两个类都要实例化么?肯定不能直接实例化接口类的,只能实例化接口类的实现类的
//怎么如何实例化呢?
public class AccountServiceImpl implements AccountService{
   //...
}
这段代码等同于:
<beans xmlns="" xmlns:xsi="" xsi:schemaLocation="">
    <bean id="accountService" class="com.wiley.beginningspring.ch2.~CAAccountServiceImpl"
          lazy-init="true">
    </bean>
</beans>

代码二:
@Configuration
//先忽略注解,看下面那个类
//类名很有意思看一哈:Ch2BeanConfiguration
//Ch2表示第二章,莫非还有第三章,第四章么?貌似啊
//BeanConfiguration表示bean配置(姑且叫bean工厂类)
//没有固化的思考,如同没根的枯草,一定会被吹得胡乱飞起!
public class Ch2BeanConfiguration{
   @Bean
   @Lazy(true)
   //忽略注解,在该类中定义了一个accountServie方法
   //注意返回值的类型:返回值的类型名称和方法名称相同
   //这说明这是一个工厂方法
   //工厂方法就是用来生产实例的
   //现在进入方法中看哈逻辑
   //工厂方法的逻辑很简单:就是调用类的构造方法然后将结果返回
   //话句话说,我调用这个工厂方法实际上只做一件事情就是实例化啊
   //到这里@Bean做了什么事情就很清楚了,
   //1.调用accountService方法
     2.将实例命名为accountService
     3.将该实例注册到spring容器,从而成为bean
   public AccountService accountService(){
       //调用AccountServiceImpl类的构造方法
       AccountServiceImpl bean = new AccountServiceImpl();
       //返回方法调用的返回值
       return bean;
       //这里要注意的是:方法的返回值的类型是AccountService
       //而构造方法的返回值的类型是AccountServiceImpl
       //按理说,类型名已经冲突了,这他妈合法么?是不是写错了?
       //如果没有写错的话
       //我们将观察到一些重要的知识:
         1 接口类肯定是不能new的
         2 接口类的实现类是可以new一个实例的
         3 接口类的实现类的实例将被视为该接口类的一个实例
         4 接口只含有一些没有方法体的方法,像是一个标准,规范一样,new是new不了了
      //人有时候就是这么简单,给他一个说法,他的内心世界就平静了
      //说实在的,猜出知识是最简单的,前提是发生在这里的一切是真的
   }
//....
}

那这段代码究竟表示什么意思呢?
既然是同一件事情的两种方式
那就换成另外一种方式表达吧
就是:
<beans xmlns="" xmlns:xsi="" xsi:schemaLocation="">
    <bean id="accountService" class="com.wiley.beginningspring.ch2.~CAAccountServiceImpl"
          lazy-init="true">
    </bean>
</beans>


总结:代码一和代码二无非就是注解的两种方式而已!!

猜你喜欢

转载自blog.csdn.net/weixin_42204641/article/details/81542232