Spring Bean的配置详解

news2024/11/15 10:30:41

目录

1.bean基础配置

例如:配置UserDaolmpl由Spring容器负责管理

2.Spring开发中主要是对Bean的配置, Bean的常用配置一览如下:

3.bean的别名配置

4.bean作用范围配置

                   5.bean的实例化

                   6.bean生命周期

                    7.Spring的get方法

                    8.Bean的延迟加载

                     9.Bean的初始化和销毁方法配置

                    10.Bean的依赖注入配置


1.bean基础配置

类别描述
名称bean
类型标签
所属beans标签
功能定义Spring核心容器管理的对象
格式

<beans>

      <bean/>

     <bean></bean>

</beans>

属性列表

id:bean的id,使用容器可以通过id值获取对应的bean,在一个容器中id值唯一

class:bean的类型,即配置的bean的全路径类名

范例

<bean id="userDao"class="com.tangyuan.dao.impl.User DaoImpl"/>

 <bean id="userService"  class="com.tangyuan.service.impl.UserServiceImpl"/>

例如:配置UserDaolmpl由Spring容器负责管理

<bean id="userDao"class="com.tangyuan.dao.impl.UserDaoImpl"/>

          此时存储到Spring容器(singleObjects单例池) 中的Bean的beanNames是userDao,值是UserDaolmpl对象, 可以根据beanName获取Bean实例

applicationContext.getBean("userDao");

      如果不配置id, 则Spring会把当前Bean实例的全限定名作为beanName

applicationContext.getBean("com.tangyuan.dao.impl.UserDaoImpl");

2.Spring开发中主要是对Bean的配置, Bean的常用配置一览如下:

Xml配置方式功能描述
<bean id=""class="">Bean的id和全限定名配置
<bean name="">通过name设置Bean的别名, 通过别名也能直接获取到Bean实例
<bean scope="">Bean的作用范围, BeanFactory作为容器时取值singleton和prototype
<bean lazy-init="">Bean的实例化时机, 是否延迟加载。BeanFactory作为容器时无效
<bean init-method="">Bean实例化后自动执行的初始化方法, method指定方法名
<bean destroy-method="">Bean实例销毁前的方法, method指定方法名
<bean auto wire="byType">设置自动注入模式, 常用的有按照类型byType, 按照名字byName
<bean factory-bean=" " factory-method=""/>指定哪个工厂Bean的哪个方法完成Bean的创建

 

3.bean的别名配置

类别描述
名称name
类型属性
所属bean标签
功能定义bean的别名,可定义多个,使用逗号(,)分号(;)空格()分隔
范例<bean id="userDao"name="aaa,bbb" class="com.tangyuan.dao.impl.UserDaoImpl"/>

注意事项:

     获取bean无论是通过id还是name获取,如果无法获取到,将会抛出异常NoSuchBeanDefinitionException:No bean named 'UserDaoImpl' available

可以为当前Bean指定多个别名, 根据别名也可以获得Bean对象

<bean id="userDao"name="aaa,bbb" class="com.tangyuan.dao.impl.UserDaoImpl"/>

         配置了别名时,如果有id设置了,那么id就是BeanName,如果没有设置id,那么BeanName就是别名第一个,如果都没有,那么class就是BeanName

      此时多个名称都可以获得UserDaolmpl实例对象

applicationContext.getBean("userDao") ;
applicationContext.getBean("aaa") ;
applicationContext.getBean("bbb") ;

4.bean作用范围配置

类别描述
名称scope
类型属性
所属bean标签
功能

定义bean的作用范围,可选范围如下:

  • singleton:单例(默认)
  •  prototype:非单例
范例<bean id="userDao"class="com.tangyuan.dao.impl.UserDaoImpl" scope="prototype"/>

     默认情况下, 单纯(基本)的Spring环境Bean的作用范围有两个:

  • Singleton和Prototype
  • singleton:单例, 默认值, Spring容器创建的时候, 就会进行Bean的实例化, 并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
  • prototype:原型, Spring容器初始化时不会创建Bean实例, 当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。
  • 注意:在webmvc环境中:-------> singleton+prototype+request和session

①:为什么bean默认为单例?

           对于Spring而言,它帮我们管理的bean要放置到Spring容器中,假定一个场景,如果造出来的bean不是非单例的,bean的数量会有无穷无尽,用一次造一个,所以Spring不是帮助我们管理这一类的bean的,这样的话,对Spring容器也会有一个特别大的压力,如果Spring造出来的bean都是单例的,对我们的业务不会造成伤害,造一个dao对象,执行完方法,下一次,你也需要再造一个dao对象,执行另一个方法,这两个对象没有什么不同的,可以直接使用这个对象。Spring帮助我们管理对象的时候,其实就是管理那些可以多用的对象,就是这个对象你用完之后,下次还可以用它,这样,效率才会更高一些,因此,它就简单一些,造出来的bean就是单例的

②.适合交给容器管理的bean

  • 表现层对象
  • 业务层对象
  • 数据层对象
  • 工具对象

③:不适合交给容器管理的bean

  • 封装实体的域对象

5.bean的实例化

构造方法

  • bean本质上就是对象,可以使用构造方法来完成bean的创建

              Spring的实例化方式主要如下两种:

  • 构造方式实例化:底层通过构造方法对Bean进行实例化 ----默认无参
  • 有参--->在xml文件中添加
  • <constructor-arg name="构造函数的参数名" value="值" ></constructor-arg>
  • 工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化

         构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化, Spring中配置的<bean>几乎都是无参 造该方式, 此处不在赘述。下面讲解有参构造方法实例化Bean

//有参构造方法
public UserDaoImpl(String name) {
​
}

            有参构造在实例化Bean时, 需要参数的注入, 通过<constructor-arg>标签, 嵌入在<bean>标签内部提供构造参 数,如下:

<bean id="userDao"class="com.tangyuan.dao.impl.UserDaoImpl">
        <constructor-arg name="name" value="秦始皇"/>  
</bean>

     注:无参构造方法如果不存在,将抛出异常BeanCreationException     

工厂方式实例化Bean

工厂方式实例化Bean, 又分为如下三种:

  • 静态工厂方法实例化Bean

  • 实例工厂方法实例化Bean

  • 实现FactoryBean规范延迟实例化Bean

静态工厂方法实例化Bean的基本操作如下:

1.创建一个静态的static方法(无参)

  public static UserDao userDao(){
            //Bean在创建之前可以进行一些其他的业务逻辑处理操作
            return  new UserDaoImpl();
        }
一个静态的static方法(有参) 
  public static UserDao userDao(String name,int age){
            //Bean在创建之前可以进行一些其他的业务逻辑处理操作
            return  new UserDaoImpl();
        }
 

2.在xml文件中进行设置

  • 无参设置------>
<!--配置MyBeanFactory-->
     <bean id="userDao1" class="com.tangyuan.factory.MyBeanFactory" factory-method="userDao"></bean>
  • 有参设置------->
 <!--配置MyBeanFactory-->
     <bean id="userDao1" class="com.tangyuan.factory.MyBeanFactory" factory-method="userDao">
         <constructor-arg name="name" value="秦始皇"></constructor-arg>
         <constructor-arg name="age" value="12"></constructor-arg>
     </bean>

3.测试

  ClassPathXmlApplicationContext applicationContext=new                  ClassPathXmlApplicationContext("applicationContext.xml");
 UserDao userDao1 = (UserDao) applicationContext.getBean("userDao1");
        System.out.println(userDao1);//com.tangyuan.dao.impl.UserDaoImpl@57536d79

实例工厂方法实例化Bean

1.创建一个方法(无参)

  public  UserDao userDao(){
            //Bean在创建之前可以进行一些其他的业务逻辑处理操作
            return  new UserDaoImpl();
        }

    创建一个方法(有参)

public  UserDao userDao(String username){
            //Bean在创建之前可以进行一些其他的业务逻辑处理操作
            return  new UserDaoImpl();
        }

2.在xml文件中进行设置----->先实例化工厂对象,再实例化Bean

  • 无参设置------->
<!--配置MyBeanFactory2工厂对象-->
    <bean id="myBeanFactory2" class="com.tangyuan.factory.MyBeanFactory2"></bean>

    <!--配置MyBeanFactory2-->
    <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"></bean>
  • 有参设置------>
 <!--配置MyBeanFactory2工厂对象-->
    <bean id="myBeanFactory2" class="com.tangyuan.factory.MyBeanFactory2"></bean>

    <!--配置MyBeanFactory2-->
    <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao">
        <constructor-arg name="username" value="秦始皇"></constructor-arg>
    </bean>

3.测试

 ClassPathXmlApplicationContext applicationContext=new                  ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao2 = (UserDao) applicationContext.getBean("userDao2");
System.out.println(userDao2);//com.tangyuan.dao.impl.UserDaoImpl@3b0143d3

实现FactoryBean规范延迟实例化Bean

1.创建一个类,继承FactoryBean<T>接口,并实现其中的方法

package com.tangyuan.factory;

import com.tangyuan.dao.UserDao;
import com.tangyuan.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;

/**
 * @author 唐渊
 * @create  2022-11-21 11:16
 */
public class MyBeanFactory3 implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    //返回Bean的类型
    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

2.在xml文件中进行设置

 <!--配置MyBeanFactory3-->
    <bean id="userDao3" class="com.tangyuan.factory.MyBeanFactory3"></bean>

3.测试--------getBean()方法之后,才会调用getObject()方法

ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao3 = (UserDao) applicationContext.getBean("userDao3");
        System.out.println(userDao3);//com.tangyuan.dao.impl.UserDaoImpl@1e965684

注:这里的bean是单例模式

        如果,需要改成非单例的,在类中添加下面的方法,并返回false即可,如果想改为单例的,返回ture,或者不写,默认是单例

public boolean isSingleton(){
   return false;
}

6.bean生命周期

  • 生命周期:从创建到消亡的完整过程
  • bean生命周期:bean从创建到销毁的整体过程
  • bean生命周期控制:在bean创建后到销毁前做一些事情

           Spring Bean的生命周期是从Bean实例化之后, 即通过反射创建出对象之后, 到Bean成为一个完整对象, 最终存储 到单例池中, 这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:

  • Bean的实例化阶段:Spring框架会取出Bean Definition的信息进行判断当前Bean的范围是否是singleton的, 是否不是延迟加载的, 是否不是Factory Bean等, 最终将一个普通的singleton的Bean通过反射进行实例化;

  • Bean的初始化阶段:Bean创建之后还仅仅是个"半成品", 还需要对Bean实例的属性进行填充、执行一些Aware 接口方法、执行Bean PostProcessor方法、执行Initializing Bean接口的初始化方法、执行自定义初始化init方法 等。该阶段是Spring最具技术含量和复杂度的阶段, Aop增强功能, 后面要学习的Spring的注解功能等、 spring高频面试题Bean的循环引用问题都是在这个阶段体现的;

  • Bean的完成阶段:经过初始化阶段, Bean就成为了一个完整的Spring Bean, 被存储到单例池 singleton Objects中去了, 即完成了Spring Bean的整个生命周期。

        由于Bean的初始化阶段的步骤比较复杂, 所以着重研究Bean的初始化阶段 Spring Bean的初始化过程涉及如下几个过程:

  • Bean实例的属性填充

  • Aware接口属性注入

  • BeanPostProcessor的before() 方法回调

  • InitializingBean接口的初始化方法回调

  • 自定义初始化方法init回调

  • BeanPostProcessor的after() 方法回调

ps:执行顺序-------InitializingBean接口的初始化方法--->自定义初始化方法init----->BeanPostProcessor的before() 方法------>BeanPostProcessor的after()

        Bean实例属性填充 BeanDefinition中有对当前Bean实体的注入信息通过属性propertyValues进行了存储

Bean实例属性填充 Spring在进行属性注入时, 会分为如下几种情况:

  • 注入普通属性, String、int或存储基本类型的集合时, 直接通过set方法的反射设置进去;

  • 注入单向对象引用属性时, 从容器中getBean获取后通过set方法反射设置进去, 如果容器中没有, 则先创建被 注入对象Bean实例(完成整个生命周期) 后, 在进行注入操作;

  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案。

         单向:service的创建依赖dao的注入,dao的注入不需要service的注入

        步骤:UserService创建----->UserDao创建----->UserService执行注入UserDao的操作:setUserDao方法执行

          多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"

         beanA ----A依赖于B--------><--------B依赖于A-----beanB

public class User ServiceImpl implements User Service{
​      public void setUserDao(UserDao userDao){}
}
public class UserDaoImpl  implements UserDao{
​    public void setUserService(UserService userService) {}
}
<bean id="userService"   class="com.tangyuan.service.impl.UserServiceImpl">
          <property name="userService"  ref="userService"/>
</bean>
<bean id="userDao" class="com.tangyuan.dao.impl.UserDaoImpl">
​             <property name="userDao" ref="userDao"/>
</bean>

         Spring提供了三级缓存存储完整Bean实例和半成品Bean实例, 用于解决循环引用问题 在Default List able BeanFactory的上四级父类Default Singleton Bean Registry中提供如下三个Map:

public class Default singleton Bean Registry...{
//1、最终存储单例Bean成品的容器, 即实例化和初始化都完成的Bean, 称之为"一级缓存"
Map<String, Object>singleton Objects=new Concurrent HashMap(256) ;
//2、早期Bean单例池, 缓存半成品对象, 且当前对象已经被其他对象引用了, 称之为"二级缓存"
Map<String, Object>early Singleton Objects=new Concurrent HashMap(16) ;
//3、单例Bean的工厂池, 缓存半成品对象, 对象未被引用, 使用时在通过工厂创建Bean, 称之为"三级缓存"
Map<String, Object Factory<?>>singleton Factories=new HashMap(16) ;
}

UserService和UserDao循环依赖的过程结合上述三级缓存描述一下:

  • UserService实例化对象, 但尚未初始化, 将UserService存储到三级缓存;

  • UserService属性注入, 需要UserDao, 从缓存中获取, 没有UserDao;

  • UserDao实例化对象, 但尚未初始化, 将UserDao存储到到三级缓存;

  • UserDao属性注入, 需要UserService, 从三级缓存获取UserService, UserService从三级缓存移入二级缓存;

  • UserDao执行其他生命周期过程, 最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;

  • UserService注入UserDao;

  • UserService执行其他生命周期过程, 最终成为一个完成Bean,存储到一级缓存, 删除二三级缓存。

常用的Aware接口

           Aware接口是一种框架辅助属性注入的一种思想, 其他框架中也可以看到类似的接口。框架具备高度封装性, 我们接 触到的一般都是业务代码, 一个底层功能API不能轻易的获取到, 但是这不意味着永远用不到这些对象, 如果用到了 , 就可以使用框架提供的类似Aware的接口, 让框架给我们注入该对象。

Aware接口回调方法作用
ServletContextAwaresetServletContext(ServletContext context)Spring框架回调方法注入ServletContext对象,web环境下才生效
BeanFactoryAwaresetBeanFactory(BeanFactory factory)Spring框架回调方法注入beanFactory对象
BeanNameAwaresetBeanName(String beanName)Spring框架回调方法注入当前Bean在容器中的beanName
ApplicationContextAwaresetApplicationContext(ApplicationContext applicationContext)Spring框架回调方法注入applicationContext 对象

7.Spring的get方法

方法定义返回值和参数
Object getBean(String bean Name)根据beanName从容器中获取Bean实例, 要求容器中Bean唯一, 返回值为Object, 需要强转
T getBean(Classtype)根据Class类型从容器中获取Bean实例, 要求容器中Bean类型唯一, 返回值为Class类型实例, 无需强转
T get Bean(String beanName, Classtype)根据bean Name从容器中获得Bean实例, 返回值为Class类型实例, 无需强转
//根据beanName获取容器中的Bean实例, 需要手动强转
UserService userService=(UserService)
applicationContext.getBean("userService");
//根据Bean类型去容器中匹配对应的Bean实例, 如存在多个匹配Bean则报错
UserService userService2=applicationContext.getBean(UserService.class);
//根据bean Name获取容器中的Bean实例, 指定Bean的Type类型
UserService userService3=applicationContext.getBean("userService",
UserService.class);

8.Bean的延迟加载

        当lazy-init设置为true时为延迟加载, 也就是当Spring容器创建的时候, 不会立即创建Bean实例, 等待用到时在创建Bean实例并存储到单例池中去, 后续在使用该Bean直接从单例池获取即可, 本质上该Bean还是单例的

<bean id="userDao"class="com.tangyuan.dao.impl.UserDaoImpl" lazy-init="true"/>

9.Bean的初始化和销毁方法配置

          Bean在被实例化后, 可以执行指定的初始化方法完成一些初始化的操作, Bean在销毁之前也可以执行指定的销毁 方法完成一些操作,初始化方法名称和销毁方法名称通过

<bean id="userDao"class="com.tangyuan.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"/>
public class UserDaoImpl implements UserDao{

public UserDaoImpl(){System.out.println("User Dao Impl创建了...");}
public void init() {System.out.println("初始化方法...") ;}
public void destroy() {system.out.println("销毁方法...") ;}

}

          扩展:除此之外, 我们还可以通过实现InitializingBean接口, 完成一些Bean的初始化操作, 如下:

public classUserDaoImpl  implements UserDao,InitializingBean{
public UserDaoImpl(){System.out.println("User Dao Impl创建了...") ; }
Public void init() {System.out.println("初始化方法...") ; }
public void destroy() {System.out.println("销毁方法...") ; }
//执行时机早于init-method配置的方法
public void afterPropertiesSet() throws Exception{
   System.out.println("InitializingBean...") ;

}

}

10.Bean的依赖注入配置

  • 思考:向一个类中传递数据的方式有几种?
  • 普通方法(set方法)
  • 构造方法
  • 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
  • 引用类型
  • 简单类型(基本数据类型与String)

Bean的依赖注入有两种方式:

  • setter注入

  • 构造器注入

注入方式配置方式
通过Bean的set方法注入<property name="userDao"ref="userDao"/> <property name="userDao"value="秦始皇"/>
通过构造Bean的方法进行注入<constructor-arg name="name"ref="userDao"/> <constructor-arg name="name"value="秦始皇"/>

           其中, ref是reference的缩写形式, 翻译为:涉及, 参考的意思, 用于引用其他Bean的id。value用于注入普通 属性值。 ref---->对象 value----->普通值

  依赖注入的数据类型有如下三种:

  • 普通数据类型, 例如:String、int、boolean等, 通过value属性指定。

  • 引用数据类型, 例如:User D aol mpl、DataSource等, 通过ref属性指定。

  • 集合数据类型, 例如:List、Map、Properties等。

集合数据类型演示:

-------------------------------------------------------list集合----------------------------------------------------------------

1.创建list集合,并以String为基本类型,定义set方法

 //注入List
    private List<String> list;

    //set方法
    public  void  setList(List<String> list) {
        this.list = list;
    }
  //输出list集合
    @Override
    public  void  show(){
        System.out.println(list);
    }

2.在xml文件中进行配置

<!--配置List集合-->
<bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
    <!--list是一个属性-->
    <property name="list">
        <!--集合用子标签-->
        <list>
            <!--String为一个字符串,用value普通值-->
            <value>秦始皇</value>
            <value>唐太宗</value>
            <value>唐玄宗</value>
        </list>
    </property>
</bean>
  

3.测试

  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
 IUserService userService = (IUserService) applicationContext.getBean("userService");
userService.show();//[秦始皇, 唐太宗, 唐玄宗]

1.创建list集合,并以对象为基本类型,定义set方法

 //对象
    private List<UserDao> userDaoList;
    //set方法
    public void setUserDaoList(List<UserDao> userDaoList) {
        this.userDaoList = userDaoList;
    }

    //输出list集合
    @Override
    public  void  show(){
        System.out.println(userDaoList);
    }

2.在xml文件中进行配置

<!--配置List集合-->
<bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
    <property name="userDaoList">
        <list>
            <!--方式一:-->
             <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
             <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
             <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
        </list>
    </property>
</bean>
<!--配置List集合-->
    <bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
                <!--方式二-->
                <ref bean="userDao1"></ref>
                <ref bean="userDao2"></ref>
                <ref bean="userDao3"></ref>
            </list>
        </property>
    </bean>

    <!--方式二-->
    <bean id="userDao1" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
    <bean id="userDao2" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
    <bean id="userDao3" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
   </beans>

-----------------------------------------------------------------------set集合---------------------------------------------

1.创建set集合,并以String为基本类型,定义set方法

 //set 基本数据类型
    private Set<String> set;

    public void setSet(Set<String> set) {
        this.set = set;
    }
    //输出集合
    @Override
    public  void  show(){  
        System.out.println(set);
    }

2.在xml文件中进行配置

 <!--配置集合-->
    <bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">      
        <!--set String基本数据类型-->
        <property name="set">
            <!--set 集合-->
            <set>
                <!--String 基础类型-->
                <value>李太白</value>
                <value>杨玉环</value>
                <value>李隆基</value>
            </set>
        </property>
    </bean>

1.创建set集合,并以对象为数据类型,定义set方法

//set 对象数据类型
    private Set<UserDao> userDaoSet;

    public void setUserDaoSet(Set<UserDao> userDaoSet) {
        this.userDaoSet = userDaoSet;
    }
     //输出集合
    @Override
    public  void  show(){  
        System.out.println(userDaoSet);
    }

2.在xml文件中进行配置

 <!--配置集合-->
 <bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
        <!--Set 对象数据类型-->
     <property name="userDaoSet">
         <!--set 集合-->
         <set>
             <!--对象类型-->
             <!--方式一:-->
           <!--  <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
             <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
             <bean class="com.tangyuan.dao.impl.UserDaoImpl"></bean>-->
             <!--方式二:-->
             <ref bean="userDao1"></ref>
             <ref bean="userDao2"></ref>
             <ref bean="userDao3"></ref>
         </set>
     </property>
   </bean>

 <!--方式二-->
 <bean id="userDao1" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
 <bean id="userDao2" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
 <bean id="userDao3" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>

-------------------------------------------------------------------------map集合--------------------------------------------

1.创建map集合

 //map集合
private Map<String,UserDao> map;
public void setMap(Map<String, UserDao> map) {
    this.map = map;
}
 //输出集合
    @Override
    public  void  show(){
        System.out.println(map);
    }

2.在xml文件中进行配置

<!--配置集合-->
 <bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
     <!--map集合-->
     <property name="map">
         <map>
             <entry key="aa" value-ref="userDao2"></entry>
             <entry key="bb" value-ref="userDao1"></entry>
         </map>
     </property>
 </bean>

 <!--方式二-->
 <bean id="userDao1" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
 <bean id="userDao2" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>
 <bean id="userDao3" class="com.tangyuan.dao.impl.UserDaoImpl"></bean>

----------------------------------------------------Properties---------------------------------------------------------------

1.创建Properties集合,定义set方法,并打印输出

//Java.util.Properties包,读取Java的properties配置文件,以<key(键),value(值)>的格式来存储内容/参数配置
private Properties properties;

public void setProperties(Properties properties) {
    this.properties = properties;
}

//输出集合
@Override
public  void  show(){
    System.out.println(properties);
}

2.在xml文件中进行配置

<!--配置集合-->
    <bean id="userService" class="com.tangyuan.service.impl.UserServiceImpl">
          <!--Properties-->
        <property name="properties">
            <props>
                <prop key="aa">王昭君</prop>
                <prop key="bb">西施</prop>
                <prop key="cc">貂蝉</prop>
                <prop key="dd">杨玉环</prop>
            </props>
        </property>
    </bean>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

57. 数据增广 / 图像增广 代码实现

1. 图像增广 在对常用图像增广方法的探索时&#xff0c;我们将使用下面这个尺寸为400 x 500的图像作为示例。 从github上把img下载下来后&#xff0c;放到同一目录下&#xff1a; d2l.set_figsize() img d2l.Image.open(./img/cat1.jpg) d2l.plt.imshow(img);大多数图像增广…

数字通信系统和模拟通信系统的简单介绍

关于数字和模拟&#xff0c;比较形象的一个对比如下图所示。 模拟系统就好比传统的钟表&#xff0c;秒钟一直在走&#xff0c;也就是连续之意&#xff1b;而数字系统相当于数字表&#xff0c;“ &#xff1a;”的闪烁相当于二进制的 0 和 1&#xff0c;有离散之意。 模拟通信系…

a billion ways to grasp

https://blog.csdn.net/weixin_26752765/article/details/108132661 翻译自 https://darshanhegde.github.io/blog/2020/heuristics-for-robotic-grasping/ 讲述了各种抓取 https://rpal.cse.usf.edu/competition_iros2021/ Grasping is one of the fundamental subtask of a r…

ECCV 2022|DynamicDepth:动态场景下的多帧自监督深度估计

&#x1f3c6;前言&#xff1a;本文别名DynamicDepth (github),如本文的名字所示&#xff0c;本文着重处理的就是动态场景下的多帧自监督深度估计问题。因为MVS在动态场景下会失效&#xff0c;所以在动态区域的多帧深度并不可靠。现在的已有方法例如ManyDepth&#xff0c;利用t…

老王linux面试题汇总

1.统计一个网站的访问量&#xff0c;统计网站访问次数最多的前几名的IP地址。 2.取两个文件的相同和不同行 3.分别创建10个账号&#xff08;user1-user10&#xff09; 5.独立磁盘冗余阵列RAID O,1,5,6,10,01级别区别 5.1磁盘利用率 5.2最少几盘磁盘实现 5.3容错性&#xff0c;…

(十二)大白话对于VARCHAR这种变长字段,在磁盘上到底是如何存储的?

文章目录 1、一行数据在磁盘上存储的时候,包含哪些东西?2、变长字段在磁盘中是怎么存储的?3、存储在磁盘文件里的变长字段,为什么难以读取?4、引入变长字段的长度列表,解决一行数据的读取问题5、引入变长字段长度列表后,如何解决变长字段的读取问题?6、如果有多个变长字…

蒙特卡洛积分、重要性采样、低差异序列

渲染公式 渲染的目标在于计算周围环境的光线有多少从表面像素点反射到相机视口中。要计算总的反射光&#xff0c;每个入射方向的贡献&#xff0c;必须将他们在半球上相加&#xff1a; 为入射光线 与法线 的夹角,为方便计算可以使用法线向量和入射向量&#xff08;单位化&…

Linux|科普扫盲帖|配置网络软件源---阿里云镜像仓库服务使用(centos,Ubuntu)

前言&#xff1a; 部署搭建各种环境&#xff0c;例如&#xff0c;集群环境&#xff0c;编译环境&#xff0c;测试环境&#xff0c;桌面环境&#xff0c;lnmp环境等等以及修复各种各样的漏洞&#xff0c;基本是使用本地仓库就可以完成的&#xff0c;但本地仓库有一个比较致命的…

深入理解TDNN(Time Delay Neural Network)——兼谈x-vector网络结构

概述 TDNN&#xff08;Time Delay Neural Network&#xff0c;时延神经网络&#xff09;是用于处理序列数据的&#xff0c;比如&#xff1a;一段语音、一段文本将TDNN和统计池化&#xff08;Statistics Pooling&#xff09;结合起来&#xff0c;正如x-vector的网络结构&#x…

x86_64架构的VINS-fusion-GPU部署

x86_64架构的VINS-fusion-GPU部署 1. 环境配置&#xff08;Ubuntu 18.04&#xff09; &#xff08;0&#xff09;CUDA 10.2 安装 由于笔记本的GPU太老&#xff08;GeForce 840M&#xff09;&#xff0c;只能使用较低版本的 CUDA&#xff0c;但是也能有个好处就是能够同时兼顾…

Linux TCP 拥塞正反馈 bad case

前置知识&#xff0c;TCP thin stream&#xff0c;参见&#xff1a; 该文档中搜索 tcp_thin_linear_timeoutsTCP-thin-stream 看图说话&#xff1a; 参见 tcp_retransmit_timer 函数&#xff0c;着重看下面段落&#xff1a; if (sk->sk_state TCP_ESTABLISHED &&am…

视觉SLAM学习路线

导师让我了解SLAM&#xff0c;SLAM原本是比较小众的方向&#xff0c;最近自动驾驶火起来&#xff0c;做这个SLAM的人也多了&#xff0c;反过来也会推动机器人感知的发展。希望未来学成的时候&#xff0c;能赶上机器人大规模普及&#xff0c;就业一片蓝海。学SLAM方向跟motion p…

RabbitMQ延迟列队的使用

目录 1. 延迟队列使用场景 2. RabbitMQ中的延迟队列实现思路 3. 实现示例 3。运行项目测试 1. 延迟队列使用场景 延迟队列一般可用于具有时间限制的任务&#xff0c;例如&#xff1a;限时优惠&#xff0c;超时的订单处理等。 对于这种场景&#xff0c;传统的处理方式是任…

Ceph: ceph基础知识

ceph基础知识 一、基础概念 ceph官方文档 http://docs.ceph.org.cn/ ceph中文开源社区 http://ceph.org.cn/ 1、概述 Ceph是可靠的、可扩展的、统一的、开源分布式的存储系统。 Ceph是一个统一的分布式存储系统&#xff0c;设计初衷是提供较好的性能、可靠性和可扩展性。 C…

Python基础知识(一)

目录 输入输出函数 输入函数&#xff1a;input() 输出函数&#xff1a;print() 算术运算符 关系运算符 逻辑运算符 变量 1.命名规则 2.变量类型 3.动态类型特性 输入输出函数 输入函数&#xff1a;input() name input("请输入&#xff1a;") print(nam…

第二证券|北向资金全年净买入约900亿元 哪些行业和个股成“香饽饽”

2022年A股收官。回顾这一年&#xff0c;面临复杂严峻的国内外环境&#xff0c;A股商场推动完善多元融资支撑机制&#xff0c;加大了对实体经济的金融支撑力度&#xff0c;为中国经济V形复苏做出了奉献。这一年&#xff0c;A股IPO融资规划创出历史新高&#xff0c;存量上市公司打…

驱动的并发和竞争

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、什么是并发&#xff1f;并发并行并发并行模式二、什么是竞争三、如何解决竞争1、原子操作整形原子操作&#xff1a;原子位操作2.自旋锁3.信号量4.互斥锁5.如…

mysql批量更新方法

mysql批量更新方法 实验mysql版本为5.7.20 隔离级别为rr&#xff0c;加锁场景的问题在mysql8.0.18中为复现 方法一 replace into 批量更新 原理&#xff1a;replace into table (col1,col2) values (x1,x2), 操作本质是对重复的记录先delete 后insert 缺点&#xff1a;1、如…

特斯拉Model S及Model X 2023上半年交付,1月6日公布售价

特斯拉Model S及Model X终于快要交付了。 2022年12月30日&#xff0c;广州国际车展盛大开幕。众多车企带来了旗舰车型&#xff0c;让观众直呼太过瘾&#xff0c;其中&#xff0c;人流量爆火的莫过于特斯拉展台。此次&#xff0c;特斯拉携旗下S3XY家族重磅出击&#xff0c;全新车…

【C++基础】08:模板

模板 OVERVIEW模板一、函数模板1.func template基本使用&#xff1a;2.func template案例&#xff1a;数组排序3.函数与函数模板的区别&调用规则&#xff1a;4.func template的局限性&#xff1a;二、类模板1.类模板基本使用&#xff1a;2.类模板与函数模板的区别&#xff…