一段代码彻底弄清依赖注入中构造函数注入和setter注入的区别

先来看一个setter注入:(注入的是其他bean)

//写bean标签 配置id class
//添加property子标签 配置name ref(如果注入的是其他bean就配置name和ref)
<bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
</bean>

再来看一个setter注入(注入的是纯粹值)

<bean id="account1" class="com.wiley.beginningspring.ch2.Account">
    <property name="id" value="1"/>
    <property name="ownerName" value="John"/>
    <property name="balance" value="10.0"/>
    <property name="locked" value="false"/>
</bean>

再再看一个setter注入(注入的还是纯粹值)
<bean id="account2" class="com.wiley.beginningspring.ch2.Account">
    <property name="id" value="2"/>
    <property name="ownerName" value="Mary"/>
    <property name="balance" value="20.0"/>
    <property name="locked" value="false"/>
</bean>

发现了什么没有?:
//如果是注入纯粹值 就配置name和value

再来看一个setter注入:(注入的是一个map的bean集合)

//如果是map类型的属性
//property用双标签
//只要配置一个name
//添加map子标签
//添加entry单标签
//配置key 和 value-ref
<bean id="accountDao" class="com.wiley.beginningspring.ch2.AccountDaoInMemoryImpl">        

   <property name="accountsMap">
        <map>
            <entry key="1" value-ref="account1"/>
            <entry key="1" value-ref="account2"/>
        </map>
    </property>
</bean>

恭喜你,你看完了所有类型的setter注入!!!!!!


//定义一个service实现类
public class AccountServiceImpl implements AccountService{
   //定义一个AccountDao类型的属性 accountDao; 
   private AccountDao accountDao;
   //定义该类的一个构造函数方法 接受一个AccountDao类型的参数accountDao
   public AccountServiceImpl(AccountDao accountDao){
       //将传入的参数设置给类的accountDao属性
       this.accountDao = accountDao;
   }
}

下面看一个构造函数注入:!!!
//xml文件头声明
//xml标签配置version encoding
<?xml version="" encoding=""?>
//beans标签 配置xmlns xmlns:xsi xsi:schemaLocation 
<beans xmlns="" xmlns:xsi="" xsi:schemaLocation=""> 
     //看这里!!!!
   <bean id="accountService" class="com.wiley.beginningspring.ch2.AccountServiceImpl">
       <constructor-arg ref="accountDao"/>
   </bean>

   

  <bean id="accountDao" class="com.wiley.beginnignspring.ch2.AccountDaoInMemoryImpl">
      //这里不用管  
   </bean>

</beans>

下面来实例化Spring容器 (盛放bean的瓶子)

将XMLBean定义文件作为参数来实例化spring容器
public class Main{
    public static void main(String[] args){
        ClassPathXmlApplicationContext applicationContext = 
        new ClassPathXmlApplicationContext("/com/wiley/beginningspring/ch2/ch2-beans.xml");
    }
}

从spring容器中访问accoutnService Bean 

(既然盛放了bean,需要哪个bean就取(get)哪个)
AccountService accountService = applicationContext.getBean(

                                "accountService",AccountService.class);
System.out.println("Before money transfer");

//之前对accountDao配置了map所以这里可以取到两个account(1和2)

System.out.println("Account 1 balance:" + 
                   accountService.getAccount(1).getBalance());
System.out.println("Account 2 balance:" + 
                   accountService.getAccount(2).getBalance());
accountService.transferMoney(1,2,5.0);
System.out.pringln("After money transfer");
System.out.println("Account 1 balance:" + 
                   accountService.getAccount(1).getBalance());
System.out.println("Account 2 balance :" + 
                   accountService.getAccount(2).getBalance());

看下面就会知道构造注入的实现原理!!!!!
//创建Foo类
public class Foo{
   //创建Bar类型的bar属性
   private Bar bar;
   //创建Baz类型的baz属性
   private Baz baz;
   //创建类的第一个构造函数(接受两个参数先后分别为Bar类型 和 Baz类型)
   public Foo(Bar bar,Baz baz){
      //将参数分别设置给类的bar属性和baz属性
      this.bar = bar;
      this.baz = baz;
   }
  //创建类的第二个构造函数(接受两个参数先后分别为Baz类型 和 Bar类型)
  public Foo(Baz baz,Bar bar){
      //将参数赋值给类的属性
      this.baz = baz;
      this.bar = bar;
  }
//两个构造方法的区别是参数个数类型都相同但是先后顺序不同
}


创建 Bar类
public class Bar{

}

创建 Baz类
public class Baz{

}


<bean id="foo" class="com.wiley.beginningspring.ch2.Foo">
    //通过构造函数的方法创建bean实例
    <constructor-arg ref="bar" />
    <constructor-arg ref="baz" />
    //且构造函数的参数类型分别为Bar类型 和 Baz类型
</bean>


<bean id="bar" class="com.wiley.beginningspring.ch2.Bar"/>

<bean id="baz" class="com.wiley.beginningspring.ch2.Baz"/>


问题: spring容器无法实例化fooBean

解决方法:给构造方法函数的参数加上索引 以表明先后顺序

//id的含义是该beand的标识(唯一的那种名字)
//class表明该实例bean的所属的类
//下面指明创建一个bean实例
<bean id="foo" class="com.wiley.beginningspring.ch2.Foo">
  <constructor-arg ref="bar" index="0"/>
  <constructor-arg ref="baz" index="1"/>
//这两行代码表明通过类的构造函数来创建bean实例且
//第一个参数是引用的名为bar的bean实例
//第二个参数是引用的名为baz的bean实例
</bean> 
//一个bean就是一个类实例
//只不过这个实例是spring管理的
<bean id="bar" class="com.wiley.beginningspring.ch2.Bar"/>
//读到的信息: bean实例 名为bar 所属类是Bar 
<bean id="baz" class="com.wiley.beginningspring.ch2.Baz"/> 
// bean 实例 名为baz 所属类是Baz   

看下面就知道开发中用的是两种方式的联合!!!!
//创建类Foo
public clas Foo {
   //定义Bar类型的属性 bar
   private Bar bar;
   //定义Baz类型的属性 baz
   private Baz baz;
   //定义类的构造函数 参数为Bar类型的bar
   public Foo(Bar bar){
       //将参数设置给bar属性
       this.bar  = bar;
   }
   
   //定义属性baz的setter方法
   public void setBaz(Baz baz){
       this.baz = baz;
   }
   
   
}

//定义Baz类
public Baz{

}

//定义Bar类
public Bar{


}


<bean id="foo" class="com.wiley.beginningspring.ch2.Foo">
   //调用构造函数创建实例
   <constructor-arg ref="bar"/>
   //调用属性baz的方法 传入名为baz的bean作为参数
   <property name="baz" ref="baz"/>
</bean>

<bean id="baz" class="com.wiley.beginningspring.ch2.Baz"/>

<bean id="bar" class="com.wiley.beginningspring.ch2.Bar"/>

   


 

猜你喜欢

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