spring应用手册-IOC(XML配置实现)第二部分

170 阅读10分钟

1.19beans标签的profile属性

profile用于配置spring的多环境配置。

我们可以通过profile配置多个不同环境下的配置属性。

案例:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <beans profile="test">
         <!-- 测试环境下的配置 -->
     </beans>
     <beans profile="prod">
         <!-- 生产环境下的配置 -->
     </beans>
 </beans>

spring 为我们提供了大量的激活 profile 的方法,可以通过代码来激活,也可以通过系统环境变量、JVM参数、servlet上下文参数来定义 spring.profiles.active 参数激活 profile。

ENV方式:ConfigurableEnvironment.setActiveProfiles("test")

JVM参数方式:set JAVA_OPTS="-Dspring.profiles.active=test"

web.xml方式:

 <init-param>
   <param-name>spring.profiles.active</param-name>
   <param-value>production</param-value>
 </init-param>

标注方式(junit单元测试非常实用):

 @ActiveProfiles({"unittest","productprofile"})

看案例:

我们配置如下,不同的环境下在service中注入不同的dao:

<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byType"  xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 注册accountDAO_mysql -->
    <bean id="accountDAO_mysql" autowire-candidate="false" class="com.dk.demo1.dao.impl.AccountDAO_mysql"/>
    <!-- 注册accountDAO_oracle -->
    <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
    <beans profile="mysql">
        <!-- 注册accountService  注入accountDAO_mysql -->
        <bean id="accountService" name="a_service"
               class="com.dk.demo1.service.AccountService">
            <property name="accountDAO" ref="accountDAO_mysql"/>
        </bean>
    </beans>
    <beans profile="oracle">
        <!-- 注册accountService  注入accountDAO_mysql -->
        <bean id="accountService" name="a_service"
              class="com.dk.demo1.service.AccountService">
            <property name="accountDAO" ref="accountDAO_oracle"/>
        </bean>
    </beans>
</beans>

测试:

 @Test
 public void testSpringProfile(){
     //创建spring容器
     ClassPathXmlApplicationContext ac =
             new ClassPathXmlApplicationContext("applicationContext.xml");
     //激活profile
     ConfigurableEnvironment environment = ac.getEnvironment();
     environment.setActiveProfiles("oracle");
     //重启容器
     ac.refresh();
     AccountService accountService =  ac.getBean(AccountService.class);
     accountService.save("戴着假发的程序员");
 }

1.20 property标签

property是用来给bean的属性配置要注入的值的。这些值可以是bean或者简单值(基本类型和Stirng)。

案例:

 /**
  * @author 戴着假发的程序员
  * @description
  */
 public class AccountService {
     private IAccountDAO accountDAO;
 ​
     private String appName;
 ​
     public void setAppName(String appName) {
         this.appName = appName;
     }
     public void setAccountDAO(IAccountDAO accountDAO) {
         this.accountDAO = accountDAO;
     }
     public int save(String name){
         System.out.println("AppName:"+appName);
         System.out.println("AccountService-save->保存用户:"+name);
         return accountDAO.save(name);
     }
 }
 ​

AccountService中需要注入属性IAccountDAO和appName,我们可以按照下面的方式注入:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans default-autowire="byType"  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 注册accountDAO_oracle -->
     <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
     <!-- 注册accountService  注入accountDAO_mysql -->
     <bean id="accountService" name="a_service"
           class="com.dk.demo1.service.AccountService">
         <property name="accountDAO" ref="accountDAO_oracle"/>
         <!-- 注入简单属性 -->
         <property name="appName" value="spring应用手册"/>
 <!--        <property name="appName">-->
 <!--            <value>spring应用手册</value>-->
 <!--        </property>-->
     </bean>
 </beans>

这样的配置可以让我们从spring容器中获取的accountService对象已经装配好了上面的两个属性。

测试:

     @Test
     public void testSpringProperty(){
         //创建spring容器
         ClassPathXmlApplicationContext ac =
                 new ClassPathXmlApplicationContext("applicationContext.xml");
         AccountService accountService =  ac.getBean(AccountService.class);
         accountService.save("戴着假发的程序员");
     }

控制台:

1587213909760.png

1.21 constructor-arg标签

constructor-arg标签和property一样可以通知spring帮我们注入属性。

只不过constructor-arg的配置,spring会通过构造方法注入,这时就需要我们的类中有对应的构造方法。

案例如下:

 /**
  * @author 戴着假发的程序员
  * @description
  */
 public class AccountService {
     private IAccountDAO accountDAO;//bean的引用类型
     private String appName;//简单类型(String和基本数据类型)
 ​
     public AccountService(IAccountDAO accountDAO, String appName) {
         this.accountDAO = accountDAO;
         this.appName = appName;
     }
 ​
     public int save(String name){
         System.out.println("AppName:"+appName);
         System.out.println("AccountService-save->保存用户:"+name);
         return accountDAO.save(name);
     }
 }

这时我们会发现,我们的类不再需要提供无参数的构造方法了。

配置方式如下:

我们可以根据构造方法形参的名字注入:

     <!-- 注册accountDAO_oracle -->
     <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
     <!-- 注册accountService  注入accountDAO_mysql -->
     <bean id="accountService" name="a_service"
           class="com.dk.demo1.service.AccountService">
         <!-- 使用构造方法注入属性 -->
         <constructor-arg name="accountDAO" ref="accountDAO_oracle"/>
         <constructor-arg name="appName" value="spring应用手册"/>
     </bean>

我们也可以根据参数的索引注入属性:

     <!-- 注册accountDAO_oracle -->
     <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
     <!-- 注册accountService  注入accountDAO_mysql -->
     <bean id="accountService" name="a_service"
           class="com.dk.demo1.service.AccountService">
         <!-- 使用构造方法注入属性 -->
         <constructor-arg index="0" ref="accountDAO_oracle"/>
         <constructor-arg index="1" value="spring应用手册"/>
     </bean>

当然 constructor-arg还有一个属性type用来指定参数的类型:

     <!-- 注册accountDAO_oracle -->
     <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
     <!-- 注册accountService  注入accountDAO_mysql -->
     <bean id="accountService" name="a_service"
           class="com.dk.demo1.service.AccountService">
         <!-- 使用构造方法注入属性 -->
         <constructor-arg type="com.dk.demo1.dao.IAccountDAO"
                          index="0" ref="accountDAO_oracle"/>
         <constructor-arg index="1" value="spring应用手册"/>
     </bean>

通常情况下,spring都会自动识别类型,但是如果一个bean本身拥有多个类型,这时如果我们需要指定特定的类型,就需要使用type指定类型。

1.22 lookup-method标签

lookup-method是spring实现的一种特殊的通过方法注入的方式。

我们看下面的案例:

我们有两个IAccountDAO接口的实现类:

接口:

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public interface IAccountDAO {
     public int save(String name);
 }

两个实现类:

 /**
  * @author 戴着假发的程序员
  * @description
  */
 public class AccountDAO_mysql implements IAccountDAO {
     @Override
     public int save(String name){
         System.out.println("AccountDAO_mysql-save->保存账户:"+name);
         return 1;
     }
 }
 /**
  * @author 戴着假发的程序员
  * @description
  */
 public class AccountDAO_oracle implements IAccountDAO {
     @Override
     public int save(String name){
         System.out.println("AccountDAO_oracle-save->保存账户:"+name);
         return 1;
     }
 }

我们有一个抽象的service类,如下:

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public abstract class AbstractAccountService {
     //非抽象的保存方法
     public int save(String name){
         System.out.println("AbstractAccountService-save:"+name);
         //调用抽象方法获取IAccountDAO对象
         return getAccount().save(name);
     };
     //抽象方法获取IAccountDAO
     public abstract IAccountDAO getAccount();
 }

这里注意我们的service是一个抽象类,并没有属性IAccountDAO。 我们是通过一个抽象方法getAccount()获取IAccountDAO对象的。(看到这里肯定蒙圈,继续看下面的) 配置如下:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans default-autowire="byType"  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 注册accountDAO_oracle -->
     <bean id="accountDAO_oracle"  class="com.dk.demo1.dao.impl.AccountDAO_oracle"/>
     <!-- 注册accountDAO_mysql -->
     <bean id="accountDAO_mysql"  class="com.dk.demo1.dao.impl.AccountDAO_mysql"/>
     <!--service配置  分别配置两个 -->
     <bean id="accountService_mysql"
           class="com.dk.demo1.service.AbstractAccountService">
         <!-- 通过lookup-method 通知springgetAccount方法的返回值是 accountDAO_mysql-->
         <lookup-method name="getAccount" bean="accountDAO_mysql"/>
     </bean>
     <bean id="accountService_oracle"
           class="com.dk.demo1.service.AbstractAccountService">
         <!-- 通过lookup-method 通知springgetAccount方法的返回值是 accountDAO_oracle-->
         <lookup-method name="getAccount" bean="accountDAO_oracle"/>
     </bean>
 </beans>

测试:

 @Test
 public void testLookup(){
     ApplicationContext ac =
             new ClassPathXmlApplicationContext("applicationContext-demo4.xml");
     AbstractAccountService bean1 = (AbstractAccountService) ac.getBean("accountService_mysql");
     bean1.save("戴着假发的程序员");
     AbstractAccountService bean2 = (AbstractAccountService) ac.getBean("accountService_oracle");
     bean2.save("daizhejiafadechengxuyuan");
     System.out.println(bean1);
     System.out.println(bean1);
 }

控制台

1587215632853.png 通过观察我们发现几个问题:

1、AbstractAccountService是一个抽象类,理论上spring无法创建对象。

2、getAccount是个抽象方法,理论上也无法调用。

我们仔细观察控制台输出的bean1和bean2对象,我们会发现这两个对象是通过CGLib产生的代理对象

com.dk.demo1.service.AbstractAccountServiced688190a@799d4f69 com.dk.demo1.service.AbstractAccountServiced688190a@799d4f69

所以Lookup-method的主要作用是:

1、通知spring当前类需要产生代理对象。

2、通知spring当前lookup-method标注的方法的返回值应该是bean属性指定的bean对象。

这样我们就会发现,我们可以通过一个抽象方法为一个抽象类中注入我们希望的bean对象。

1.23 replaced-method标签

replaced-method可以让我们通过配置完成对原有的bean中的方法实现进行重新替换。

看案例:

我们有一个service类,其中有一个save方法的实现

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class AccountService {
     public void save(String name){
         System.out.println("AccountService-save:"+name);
     }
 }

我们制定一个替换实现类,这个类必须试下你接口: org.springframework.beans.factory.support.MethodReplacer

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class ReplacementSaveAccount implements MethodReplacer {
     /**
      * @param o 产生的代理对象
      * @param method 替换的方法对象
      * @param objects 提花的方法传入的参数
      * @return
      * @throws Throwable
      */
     @Override
     public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {
         Object result = null;
         System.out.println("当前对象o:"+o);
         System.out.println("原来的方法method:"+method);
         for (Object arg : objects){
             System.out.println("参数--:"+arg);
         }
         System.out.println("保存账户替换后的方法");
         return result;
     }
 }

配置如下:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 替换Bean  ReplacementSaveAccount -->
     <bean id="replacementSaveAccount" class="com.boxuewa.dk.demo2.service.ReplacementSaveAccount"/>
     <!-- accountService -->
     <bean id="accountService" class="com.boxuewa.dk.demo2.service.AccountService">
         <!-- 配置替换方法 -->
         <replaced-method name="save" replacer="replacementSaveAccount">
             <arg-type>String</arg-type>
         </replaced-method>
     </bean>
 </beans>

测试:

 @Test
 public void testReplaceMethod(){
     ApplicationContext ac =
             new ClassPathXmlApplicationContext("applicationContext-demo5.xml");
     AccountService bean = ac.getBean(AccountService.class);
     bean.save("戴着假发的程序员");
 }

结果:

 当前对象o:com.boxuewa.dk.demo2.service.AccountService$$EnhancerBySpringCGLIB$$f5322a5a@17776a8
 原来的方法method:public void com.boxuewa.dk.demo2.service.AccountService.save(java.lang.String)
 参数--:戴着假发的程序员
 保存账户替换后的方法

我们会发现spring会为我们生成一个AccountService的代理对象,并且将其save方法的实现修改为我们制定的ReplacementSaveAccount中的reimplement实现。

注意:下面配置中:

  <!-- 配置替换方法 -->
         <replaced-method name="save" replacer="replacementSaveAccount">
             <arg-type>String</arg-type>
         </replaced-method>

String可以配置任意多个。 这种情况往往用于AccountService有多个save方法的重载的情况。

1.24 value注入简单数据

我们在使用property和constructor-arg为bean注入属性时,如果属性是简单类型,我们可以通过value直接注入。

这里简单类型主要是指java的基本类型和String类型。

案例:

我们有一个Service类:

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class AccountService {
     private String appName;
     private int count;
     public void setAppName(String appName) {
         this.appName = appName;
     }
     public void setCount(int count) {
         this.count = count;
     }
     //无参数构造
     public AccountService(){}
      //有参数构造
     public AccountService(String appName,int count){
         this.appName = appName;
         this.count = count;
     }
     @Override
     public String toString(){
         return "appName:"+appName+";\r\ncount:"+count;
     }
 }

AccountService有两个简单类型的属性,我们可以通过下面的方式注入属性:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- accountService 方式1 -->
     <bean id="accountService1" class="com.dk.demo1.service.AccountService">
         <property name="appName" value="假发"/>
         <property name="count" value="100"/>
     </bean>
     <!-- accountService 方式2 -->
     <bean id="accountService2" class="com.dk.demo1.service.AccountService">
         <property name="appName"><value>程序员</value></property>
         <property name="count"><value>1000000</value></property>
     </bean>
     <!-- accountService 方式3 -->
     <bean id="accountService3" class="com.dk.demo1.service.AccountService">
         <constructor-arg name="appName" value="戴假发"/>
         <constructor-arg name="count" value="999"/>
     </bean>
     <!-- accountService 方式4 -->
     <bean id="accountService4" class="com.dk.demo1.service.AccountService">
         <constructor-arg name="appName">
             <value>有假发</value>
         </constructor-arg>
         <constructor-arg name="count">
             <value>99</value>
         </constructor-arg>
     </bean>
 </beans>

测试:

 @Test
 public void testValue(){
     ApplicationContext ac =
             new ClassPathXmlApplicationContext("applicationContext.xml");
     AccountService bean1 = (AccountService) ac.getBean("accountService1");
     AccountService bean2 = (AccountService) ac.getBean("accountService2");
     AccountService bean3 = (AccountService) ac.getBean("accountService3");
     AccountService bean4 = (AccountService) ac.getBean("accountService4");
     System.out.println(bean1);
     System.out.println(bean2);
     System.out.println(bean3);
     System.out.println(bean4);
 }

结果:

 appName:假发;
 count:100
 appName:程序员;
 count:1000000
 appName:戴假发;
 count:999
 appName:有假发;
 count:99

1.25 ref注入引用对象

当我们通知spring帮我们注入某个引用来行的对象时,我们可以使用ref通知spring注入bean的beanName。

案例:

我们有AccountDAO和AccountService类:

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class AccountDAO implements IAccountDAO {
     @Override
     public int save(String name) {
         System.out.println("AccountDAO-save:"+name);
         return 1;
     }
 }
 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class AccountService {
     private AccountDAO accountDAO;
     public void setAccountDAO(AccountDAO accountDAO) {
         this.accountDAO = accountDAO;
     }
     // 无参构造
     public AccountService(){}
     //有参构造
     public AccountService(AccountDAO accountDAO) {
         this.accountDAO = accountDAO;
     }
     public int save(String name){
         System.out.println("AccountService-save:"+name);
         return accountDAO.save(name);
     }
 }

我们可以以下面的方式配置:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!--dao-->
     <bean id="accountDAO1" class="com.boxuewa.dk.demo2.dao.impl.AccountDAO"/>
     <!-- service方式1-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <property name="accountDAO" ref="accountDAO1"/>
     </bean>
     <!-- service方式2-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <property name="accountDAO"><ref bean="accountDAO1"/></property>
     </bean>
     <!-- service方式3-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <constructor-arg name="accountDAO" ref="accountDAO1"/>
     </bean>
     <!-- service方式4-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <constructor-arg name="accountDAO"><ref bean="accountDAO1"/></constructor-arg>
     </bean>
     <!-- service方式5-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <property name="accountDAO">
             <bean class="com.boxuewa.dk.demo2.dao.impl.AccountDAO"/>
         </property>
     </bean>
     <!-- service方式6-->
     <bean id="accountService1" class="com.boxuewa.dk.demo2.service.AccountService">
         <constructor-arg name="accountDAO">
            <bean class="com.boxuewa.dk.demo2.dao.impl.AccountDAO"/>
         </constructor-arg>
     </bean>
 </beans>

测试:

     @Test
     public void testRef(){
         ApplicationContext ac =
                 new ClassPathXmlApplicationContext("applicationContext.xml");
         AccountService bean1 = (AccountService) ac.getBean("accountService1");
         AccountService bean2 = (AccountService) ac.getBean("accountService2");
         AccountService bean3 = (AccountService) ac.getBean("accountService3");
         AccountService bean4 = (AccountService) ac.getBean("accountService4");
         AccountService bean5 = (AccountService) ac.getBean("accountService5");
         AccountService bean6 = (AccountService) ac.getBean("accountService6");
         bean1.save("假发-1");
         bean2.save("假发-2");
         bean3.save("假发-3");
         bean4.save("假发-4");
         bean5.save("假发-5");
         bean6.save("假发-6");
     }

结果:

 AccountService-save:假发-1
 AccountDAO-save:假发-1
 AccountService-save:假发-2
 AccountDAO-save:假发-2
 AccountService-save:假发-3
 AccountDAO-save:假发-3
 AccountService-save:假发-4
 AccountDAO-save:假发-4
 AccountService-save:假发-5
 AccountDAO-save:假发-5
 AccountService-save:假发-6
 AccountDAO-save:假发-6

1.26 注入set集合

我们可以通过set标签对类中的set属性进行注入,无论属性是简单类型和引用类型。

案例:

准备账户类,拥有属性account,有参和无参构造方法

 /**
  * @author 戴着假发的程序员
  *  
  * @description 账户
  */
 public class Account {
     private String account;
     public Account(){
     }
     public Account(String account) {
         this.account = account;
     }
     public void setAccount(String account) {
         this.account = account;
     }
     @Override
     public String toString(){
         return "account:"+account;
     }
 }

准备账户组类,这个类拥有两个set集合类型的属性,一个accName存储字符串类型的账户名字,一个存储Account类型的账户对象。 拥有有参和无参构造方法。

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class Group {
     //账户名字集合
     private Set<String> accNames;
     //账户对象集合
     private Set<Account> accounts;
 ​
     public void setAccNames(Set<String> accNames) {
         this.accNames = accNames;
     }
     public void setAccounts(Set<Account> accounts) {
         this.accounts = accounts;
     }
     //无参数构造
     public Group(){
     }
     //有参数构造
     public Group(Set<String> accNames, Set<Account> accounts) {
         this.accNames = accNames;
         this.accounts = accounts;
     }
     public void showNames(){
         for(String name : accNames){
             System.out.print(name+"\t");
         }
         System.out.println();
     }
     public void showAccount(){
         for(Account account : accounts){
             System.out.print(accounts);
         }
         System.out.println();
     }
 }

我们在配置文件中给group注入属性。使用set标签进行注入:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans default-autowire="byType"  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 准备三个accountBean -->
     <bean id="account1" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="卡卡西"/>
     </bean>
     <bean id="account2" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="佐助"/>
     </bean>
     <bean id="account3" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="鸣人"/>
     </bean>
     <!-- 注册一个group -->
     <bean id="group" class="com.dk.demo2.beans.Group">
         <property name="accNames">
             <!-- 使用set标签注入简单set集合属性 -->
             <set>
                 <value>路飞</value>
                 <value>索隆</value>
                 <value>山治</value>
             </set>
         </property>
         <property name="accounts">
             <!-- set标签注入引用类型属性 -->
             <set>
                 <ref bean="account1"/>
                 <ref bean="account2"/>
                 <ref bean="account3"/>
             </set>
         </property>
     </bean>
 </beans>

测试:

 @Test
 public void testSet(){
     ApplicationContext ac =
             new ClassPathXmlApplicationContext("applicationContext.xml");
     Group bean = ac.getBean(Group.class);
     bean.showNames();
     bean.showAccount();
 }

结果:

1586052619375.png 当然对应引用类型其实我们也可以在set标签中利用bean标签直接实例化对象,例如:

 <bean id="group" class="com.boxuewa.dk.demo2.beans.Group">
     <property name="accNames">
         <!-- 使用set标签注入简单set集合属性 -->
         <set>
             <value>路飞</value>
             <value>索隆</value>
             <value>山治</value>
         </set>
     </property>
     <property name="accounts">
         <!-- set标签注入引用类型属性 -->
         <set>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="乔峰"/>
             </bean>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="虚竹"/>
             </bean>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="段誉"/>
             </bean>
         </set>
     </property>
 </bean>

测试结果:

1586052774538.png 注意:上面的所有注入方式也都适合构造方法的注入。例如:

 <!-- 注册一个group -->
 <bean id="group" class="com.dk.demo2.beans.Group">
     <constructor-arg name="accNames">
         <!-- 使用set标签注入简单set集合属性 -->
         <set>
             <value>路飞</value>
             <value>索隆</value>
             <value>山治</value>
         </set>
     </constructor-arg>
     <constructor-arg name="accounts">
         <!-- set标签注入引用类型属性 -->
         <set>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="乔峰"/>
             </bean>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="虚竹"/>
             </bean>
             <bean class="com.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="段誉"/>
             </bean>
         </set>
     </constructor-arg>
 </bean>

1.27 注入list集合

list集合的注入和set集合的注入基本完全相同。

案例

我们修改上面案例中的类型即可:

准备账户类,拥有属性account,有参和无参构造方法

 /**
  * @author 戴着假发的程序员
  *  
  * @description 账户
  */
 public class Account {
     private String account;
     public Account(){
     }
     public Account(String account) {
         this.account = account;
     }
     public void setAccount(String account) {
         this.account = account;
     }
     @Override
     public String toString(){
         return "account:"+account;
     }
 }

准备账户组类,这个类拥有两个set集合类型的属性,一个accName存储字符串类型的账户名字,一个存储Account类型的账户对象。 拥有有参和无参构造方法。

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class Group {
     //账户名字集合
     private List<String> accNames;
     //账户对象集合
     private List<Account> accounts;
 ​
     public void setAccNames(List<String> accNames) {
         this.accNames = accNames;
     }
     public void setAccounts(List<Account> accounts) {
         this.accounts = accounts;
     }
     //无参数构造
     public Group(){
     }
     //有参数构造
     public Group(List<String> accNames, List<Account> accounts) {
         this.accNames = accNames;
         this.accounts = accounts;
     }
     public void showNames(){
         for(String name : accNames){
             System.out.print(name+"\t");
         }
         System.out.println();
     }
     public void showAccount(){
         for(Account account : accounts){
             System.out.print(account);
         }
         System.out.println();
     }
 }

我们在配置文件中给group注入属性。使用list标签进行注入:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans default-autowire="byType"  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 准备三个accountBean -->
     <bean id="account1" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="卡卡西"/>
     </bean>
     <bean id="account2" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="佐助"/>
     </bean>
     <bean id="account3" class="com.dk.demo2.beans.Account">
         <constructor-arg name="account" value="鸣人"/>
     </bean>
     <!-- 注册一个group -->
     <bean id="group1" class="com.dk.demo2.beans.Group">
         <property name="accNames">
             <!-- 使用list标签注入简单set集合属性 -->
             <list>
                 <value>路飞</value>
                 <value>索隆</value>
                 <value>山治</value>
             </list>
         </property>
         <property name="accounts">
             <!-- list标签注入引用类型属性 -->
             <list>
                 <ref bean="account1"/>
                 <ref bean="account2"/>
                 <ref bean="account3"/>
             </list>
         </property>
     </bean>
 ​
     <bean id="group2" class="com.dk.demo2.beans.Group">
         <property name="accNames">
             <!-- 使用list标签注入简单set集合属性 -->
             <list>
                 <value>路飞</value>
                 <value>索隆</value>
                 <value>山治</value>
             </list>
         </property>
         <property name="accounts">
             <!-- set标签注入引用类型属性 -->
             <list>
                 <bean class="com.dk.demo2.beans.Account">
                     <constructor-arg name="account" value="乔峰"/>
                 </bean>
                 <bean class="com.dk.demo2.beans.Account">
                     <constructor-arg name="account" value="虚竹"/>
                 </bean>
                 <bean class="com.dk.demo2.beans.Account">
                     <constructor-arg name="account" value="段誉"/>
                 </bean>
             </list>
         </property>
     </bean>
 </beans>

测试:

     @Test
     public void testList(){
         ApplicationContext ac =
                 new ClassPathXmlApplicationContext("applicationContext.xml");
         Group bean1 = ac.getBean("group1",Group.class);
         bean1.showNames();
         bean1.showAccount();
         System.out.println("------------");
         Group bean2 = ac.getBean("group2",Group.class);
         bean2.showNames();
         bean2.showAccount();
     }

结果:

1587277204540.png 其余的测试和set完全一致。

1.28 注入map集合

map集合和list、set的不同是,map是双列集合。所以注入时稍有不同,但是大致一样。

要使用标签 map 和 entry。 我们看案例:

准备Account类。拥有属性account,有参和无参构造方法。

 /**
  * @author 戴着假发的程序员
  *  
  * @description 账户
  */
 public class Account {
     private String account;
     public Account(){
     }
     public Account(String account) {
         this.account = account;
     }
     public void setAccount(String account) {
         this.account = account;
     }
     @Override
     public String toString(){
         return "account:"+account;
     }
 }

准备group类,拥有两个map集合,其中一个存储账户名字(String)类型,以账号(Integer)作为key。另一个存储Account对象,以账号(Integer)作为key。并且提供有参数构造和无参数构造。

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class Group {
     //账户名字集合
     private Map<Integer,String> accNames;
     //账户对象集合
     private Map<Integer,Account> accounts;
 ​
     public void setAccNames(Map<Integer,String> accNames) {
         this.accNames = accNames;
     }
     public void setAccounts(Map<Integer,Account> accounts) {
         this.accounts = accounts;
     }
     //无参数构造
     public Group(){
     }
     //有参数构造
     public Group(Map<Integer,String> accNames, Map<Integer,Account> accounts) {
         this.accNames = accNames;
         this.accounts = accounts;
     }
     public void showNames(){
         System.out.println(accNames);
     }
     public void showAccount(){
         System.out.println(accounts);
     }
 }

在配置文件中进行注入:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 准备三个accountBean -->
     <bean id="account1" class="com.boxuewa.dk.demo2.beans.Account">
         <constructor-arg name="account" value="卡卡西"/>
     </bean>
     <bean id="account2" class="com.boxuewa.dk.demo2.beans.Account">
         <constructor-arg name="account" value="佐助"/>
     </bean>
     <bean id="account3" class="com.boxuewa.dk.demo2.beans.Account">
         <constructor-arg name="account" value="鸣人"/>
     </bean>
     <!-- 注册一个group -->
     <bean id="group" class="com.boxuewa.dk.demo2.beans.Group">
         <property name="accNames">
             <!-- 使用set标签注入简单set集合属性 -->
             <map>
                 <entry key="9527" value="路飞"/>
                 <entry key="9528" value="佐助"/>
                 <entry key="9529"><value>鸣人 </value></entry>
             </map>
         </property>
         <property name="accounts">
             <!-- set标签注入引用类型属性 -->
             <map>
                 <entry key="110"> <ref bean="account1"/></entry>
                 <entry key="111"> <ref bean="account2"/></entry>
                 <entry key="112" value-ref="account3"/>
             </map>
         </property>
     </bean>
 </beans>

测试:

     @Test
     public void testMap(){
         ApplicationContext ac =
                 new ClassPathXmlApplicationContext("applicationContext.xml");
         Group bean1 = ac.getBean("group1",Group.class);
         bean1.showNames();
         bean1.showAccount();
     }

1587296257656.png 注意几个问题:

1、上面的注入方式同样适合构造方法的注入:

 <!-- 注册一个group -->
 <bean id="group" class="com.boxuewa.dk.demo2.beans.Group">
     <constructor-arg name="accNames">
         <!-- 使用set标签注入简单set集合属性 -->
         <map>
             <entry key="9527" value="路飞"/>
             <entry key="9528" value="佐助"/>
             <entry key="9529"><value>鸣人 </value></entry>
         </map>
     </constructor-arg>
     <constructor-arg name="accounts">
         <!-- set标签注入引用类型属性 -->
         <map>
             <entry key="110"> <ref bean="account1"/></entry>
             <entry key="111"> <ref bean="account2"/></entry>
             <entry key="112" value-ref="account3"/>
         </map>
     </constructor-arg>
 </bean>

2、同样我们可以在注入bean的同时实例化:

 <constructor-arg name="accounts">
     <!-- set标签注入引用类型属性 -->
     <map>
         <entry key="110"> <ref bean="account1"/></entry>
         <entry key="111"> <ref bean="account2"/></entry>
         <entry key="112" value-ref="account3"/>
         <entry key="112">
             <bean class="com.boxuewa.dk.demo2.beans.Account">
                 <constructor-arg name="account" value="翠花"/>
             </bean>
         </entry>
     </map>
 </constructor-arg>

3、map的key可以是任何类型,所以其实map的可以也可使用 key-ref引用其他类型,当然就需要你自己制定一个专门的类型作为key。 这种方式我们一般都会使用。

1.29 注入props集合

props标签是用来注入java中的Properties类型的。我们知道Properties其实是继承了Hashtable,所以它也是双列集合,所以注入方式和map几乎相同,只是key和value的类型都是String,所以注入方式略有不同。看案例: 准备group类,拥有两个Properties集合,其中一个存储账户名字(String)类型,以账号(String)作为key。

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class Group {
     //账户名字集合
     private Properties accNames;
     public void setAccNames(Properties accNames) {
         this.accNames = accNames;
     }
     //无参数构造
     public Group(){
     }
     //有参数构造
     public Group(Properties accNames) {
         this.accNames = accNames;
     }
     public void showNames(){
         System.out.println(accNames);
     }
 }

我们在配置文件中进行注入:

 <?xml version="1.0" encoding="UTF-8"?>
 <beans  default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 注册一个group -->
     <bean id="group" class="com.boxuewa.dk.demo2.beans.Group">
         <property name="accNames">
             <!-- 使用props标签注入简单Properties集合属性 -->
             <props>
                 <prop key="9527">卡卡西</prop>
                 <prop key="9528">佐助</prop>
                 <prop key="9529">鸣人</prop>
             </props>
         </property>
     </bean>
 </beans>
         

测试:

   @Test
     public void testMap(){
         ApplicationContext ac =
                 new ClassPathXmlApplicationContext("applicationContext.xml");
         Group bean1 = ac.getBean("group1",Group.class);
         bean1.showNames();
     }

结果:

1586055051177.png

未完待续。。。。。。欢迎关注