深入理解 Spring IoC -- 基于 XML 的 Bean 配置详解

📅 2026/8/13 9:55:33
深入理解 Spring IoC -- 基于 XML 的 Bean 配置详解
一. 基于xml方式Bean的配置Spring开发中主要是对Bean的配置Bean的常用配置一览如下xml配置方式功能描述bean id classBean的id和全限定名配置bean name通过name设置Bean的别名通过别名也能直接获取到Bean实例bean scopeBean的作用范围BeanFactory作为容器时取值singleton和prototypebean lazy-initBean的实例化时机是否延迟加载。BeanFactory作为容器时无效bean init-methodBean实例化后自动执行的初始化方法method指定方法名bean destroy-methodBean实例销毁前的方法method指定方法名bean autowirebyType设置自动注入模式常用的有按照类型byType按照名字byNamebean factory-bean factory-method/指定哪个工厂Bean的哪个方法完成Bean的创建1.1 基础配置例如配置UserDaoImpl由Spring容器负责管理 beaniduserDaoclass“com.itheima.dao.impl.UserDaoImpl”/ bean此时存储到Spring容器singleObjects单例池中的Bean的beanName是userDao值是UserDaoImpl对象可以根据beanName获取Bean实例applicationContext.getBean(“userDao”);如果不配置id则Spring会把当前Bean实例的全限定名作为beanNameapplicationContext.getBean(“com.itheima.dao.impl.UserDaoImpl”);1.2 别名配置2Bean的别名配置可以为当前Bean指定多个别名根据别名也可以获得Bean对象 bean id“userDao”name666,aaaclass“com.itheima.dao.impl.UserDaoImpl”// bean此时多个名称都可以获得UserDaoImpl实例对象applicationContext.getBean(“userDao”);applicationContext.getBean(“aaa”);applicationContext.getBean(“666”);1.3 Bean的作用范围默认情况下单纯的Spring环境Bean的作用范围有两个Singleton和Prototypesingleton单例默认值Spring容器创建的时候就会进行Bean的实例化并存储到容器内部的单例池中每次getBean时都是从单例池中获取相同的Bean实例prototype原型Spring容器初始化时不会创建Bean实例当调用getBean时才会实例化Bean每次getBean都会创建一个新的Bean实例。 bean id“userDao” class“com.itheima.dao.impl.UserDaoImpl”scopesingleton/当scope设置为singleton时获得两次对象打印结果是一样的1.4 Bean的延迟加载当lazy-init设置为true时为延迟加载也就是当Spring容器创建的时候不会立即创建Bean实例等待用到时在创建Bean实例并存储到单例池中去后续在使用该Bean直接从单例池获取即可本质上该Bean还是单例的。 bean id“userDao” class“com.itheima.dao.impl.UserDaoImpl”lazy-inittrue/1.5 Bean的初始化和销毁方法配置Bean在被实例化后可以执行指定的初始化方法完成一些初始化的操作Bean在销毁之前也可以执行指定的销毁方法完成一些操作初始化方法名称和销毁方法名称通过。 bean id“userDao” class“com.itheima.dao.impl.UserDaoImpl”init-methodinit destroy-methoddestroy/publicclassUserDaoImplimplementsUserDao{publicUserDaoImpl(){System.out.println(UserDaoImpl创建了...);}publicvoidinit(){System.out.println(初始化方法...);}publicvoiddestroy(){System.out.println(销毁方法...);}}扩展除此之外我们还可以通过实现 InitializingBean 接口完成一些Bean的初始化操作如下publicclassUserDaoImplimplementsUserDao,InitializingBean{publicUserDaoImpl(){System.out.println(UserDaoImpl创建了...);}publicvoidinit(){System.out.println(初始化方法...);}publicvoiddestroy(){System.out.println(销毁方法...);}//执行时机早于init-method配置的方法publicvoidafterPropertiesSet()throwsException{System.out.println(InitializingBean...);}}1.6 Bean的实例化配置Spring的实例化方式主要如下两种构造方式实例化底层通过构造方法对Bean进行实例化。工厂方式实例化底层通过调用自定义的工厂方法对Bean进行实例化。1. 构造方法实例化构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化Spring中配置的bean几乎都是无参构造该方式此处不在赘述。下面讲解有参构造方法实例化Bean//有参构造方法publicUserDaoImpl(Stringname){}有参构造在实例化Bean时需要参数的注入通过constructor-arg标签嵌入在 bean标签内部提供构造参数如下bean iduserDaoclasscom.itheima.dao.impl.UserDaoImplconstructor-arg namenamevaluehaohao//bean2. 工厂方式实例化又分为如下三种2.1 静态工厂方法实例化Bean静态工厂方法实例化Bean其实就是定义一个工厂类提供一个静态方法用于生产Bean实例在将该工厂类及其静态方法配置给Spring即可。//工厂类publicclassUserDaoFactoryBean{//静态工厂方法publicstaticUserDaogetUserDao(Stringname){//可以在此编写一些其他逻辑代码returnnewUserDaoImpl();}}bean iduserDaoclasscom.itheima.factory.UserDaoFactoryBeanfactory-methodgetUserDaoconstructor-arg namenamevaluehaohao//bean2.2 实例工厂方法实例化Bean实例工厂方法也就是非静态工厂方法产生Bean实例与静态工厂方式比较该方式需要先有工厂对象在用工厂对象去调用非静态方法所以在进行配置时要先配置工厂Bean在配置目标Bean//工厂类publicclassUserDaoFactoryBean2{//非静态工厂方法publicUserDaogetUserDao(Stringname){//可以在此编写一些其他逻辑代码returnnewUserDaoImpl();}}!--配置实例工厂Bean--bean iduserDaoFactoryBean2classcom.itheima.factory.UserDaoFactoryBean2/!--配置实例工厂Bean的哪个方法作为工厂方法--bean iduserDaofactory-beanuserDaoFactoryBean2factory-methodgetUserDaoconstructor-arg namenamevaluehaohao//bean2.3 定义工厂实现FactoryBeanpublicclassUserDaoFactoryBean3implementsFactoryBeanUserDao{publicUserDaogetObject()throwsException{returnnewUserDaoImpl();}publicClass?getObjectType(){returnUserDao.class;}}配置FactoryBean交由Spring管理即可bean iduserDaoclasscom.itheima.factory.UserDaoFactoryBean3/通过断点观察发现Spring容器创建时FactoryBean被实例化了并存储到了单例池singletonObjects中但是getObject()方法尚未被执行UserDaoImpl也没被实例化当首次用到UserDaoImpl时才调用getObject()此工厂方式产生的Bean实例不会存储到单例池singletonObjects中会存储到factoryBeanObjectCache缓存池中并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。注意如果 FactoryBean 是单例的默认它通过 getObject() 创建的对象也会被缓存每次获取都是同一个实例。如果 FactoryBean 被配置为 scope“prototype”那么每次调用 getObject() 都会创建一个新的对象不会被缓存。1.7 Bean的依赖注入配置1. 构造方法注入顾名思义就是通过类的带参构造方法来完成注入。这种方式在Bean实例化时就必须提供依赖保证了对象的完整性。使用标签constructor-arg常用属性name指定构造函数的参数名称最常用推荐。index指定参数在构造函数中的索引位置从0开始。type指定参数的数据类型用于区分重载的构造函数。value注入基本数据类型和String类型的值。ref注入其他的Bean类型引用类型。// 目标类 UserServiceImplpublicclassUserServiceImplimplementsUserService{privateStringname;privateIntegerage;privateUserDaouserDao;// 有参构造publicUserServiceImpl(Stringname,Integerage,UserDaouserDao){this.namename;this.ageage;this.userDaouserDao;}// ...省略setter/getter}XML配置bean iduserDaoclasscom.itheima.dao.impl.UserDaoImpl/bean iduserServiceclasscom.itheima.service.impl.UserServiceImpl!--通过name属性匹配构造参数名称--constructor-arg namenamevalue张三/constructor-arg nameagevalue18/!--ref引用容器中已存在的Bean--constructor-arg nameuserDaorefuserDao//bean2. Setter方法注入Spring容器通过调用Bean的Setter方法将依赖注入。这种方式更加灵活是实际开发中使用频率最高的注入方式。使用标签property常用属性name指定Setter方法对应的属性名称注意是setName去掉set后首字母小写即name。value注入基本数据类型和String类型的值。ref注入其他的Bean类型。// 目标类 UserServiceImplpublicclassUserServiceImplimplementsUserService{privateUserDaouserDao;// 必须提供Setter方法publicvoidsetUserDao(UserDaouserDao){this.userDaouserDao;}}XML配置bean iduserDaoclasscom.itheima.dao.impl.UserDaoImpl/bean iduserServiceclasscom.itheima.service.impl.UserServiceImpl!--通过property标签调用setUserDao方法--property nameuserDaorefuserDao//bean3. 复杂类型/集合类型的注入除了基本类型和引用类型Spring还支持对数组、List、Set、Map、Properties等集合类型进行注入。bean idcollectionBeanclasscom.itheima.bean.CollectionBean!--数组注入--property namemyStrsarrayvalueaaa/valuevaluebbb/value/array/property!--List集合注入--property namemyListlistvaluelist1/valuevaluelist2/value/list/property!--Set集合注入--property namemySetsetvalueset1/valuevalueset2/value/set/property!--Map集合注入--property namemyMapmapentry keyk1valuev1/entry keyk2valuev2//map/property!--Properties注入--property namemyPropspropsprop keyp1ppp1/propprop keyp2ppp2/prop/props/property/bean4. 自动装配Autowire除了手动指定依赖关系Spring 还提供了自动装配机制。通过 标签的 autowire 属性Spring 容器可以根据特定的规则自动为 Bean 注入依赖从而减少大量的 配置。常用取值byName根据属性名称Setter方法名去掉set后首字母小写自动匹配容器中 id/name 相同的 Bean 进行注入。byType根据属性的数据类型自动匹配容器中类型唯一的 Bean 进行注入。注意如果容器中存在多个相同类型的 Bean会报错。constructor与 byType 类似但作用于构造方法的参数。Spring 会根据构造参数的类型去容器中匹配 Bean。no默认值不使用自动装配必须手动配置。!--配置UserDao--bean iduserDaoclasscom.itheima.dao.impl.UserDaoImpl/!--autowirebyName:Spring会检查UserServiceImpl中的属性发现 userDao 属性 然后去容器中寻找 iduserDao的Bean自动注入。--bean iduserServiceclasscom.itheima.service.impl.UserServiceImplautowirebyName/区别1.8 Spring的其他配置标签Spring 的 xml 标签大体上分为两类一种是默认标签一种是自定义标签默认标签就是不用额外导入其他命名空间约束的标签例如 bean 标签。标签作用beans一般作为 XML 配置根标签其他标签都是该标签的子标签beanBean 的配置标签上面已经详解了此处不再阐述import外部资源导入标签alias指定 Bean 的别名标签使用较少自定义标签就是需要额外引入其他命名空间约束并通过前缀引用的标签例如 context:property-placeholder/ 标签。二. 配置非自定义Bean2.1 配置 Druid导入Druid坐标!--mysql驱动--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.49/version/dependency!--druid数据源--dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.23/version/dependency配置 DruidDataSource!--配置DruidDataSource数据源--beanclasscom.alibaba.druid.pool.DruidDataSource!--配置必要属性--property namedriverClassNamevaluecom.mysql.jdbc.Driver/property nameurlvaluejdbc://localhost:3306/mybatis/property nameusernamevalueroot/property namepasswordvalueroot//bean2.2 配置ConnectionConnection 的产生是通过DriverManager的静态方法getConnection获取的所以我们要用静态工厂方式配置beanclassjava.lang.Classfactory-methodforNameconstructor-arg nameclassNamevaluecom.mysql.jdbc.Driver//beanbean idconnectionclassjava.sql.DriverManagerfactory-methodgetConnectionscopeprototypeconstructor-arg nameurlvaluejdbc:mysql:///mybatis/constructor-arg nameuservalueroot/constructor-arg namepasswordvalueroot//bean2.3 配置日期对象产生一个指定日期格式的对象原始代码按如下StringcurrentTimeStr2023-08-27 07:20:00;SimpleDateFormatsimpleDateFormatnewSimpleDateFormat(yyyy-MM-dd HH:mm:ss);DatedatesimpleDateFormat.parse(currentTimeStr);可以看成是实例工厂方式使用Spring配置方式产生Date实例bean idsimpleDateFormatclassjava.text.SimpleDateFormatconstructor-arg namepatternvalueyyyy-MM-dd HH:mm:ss//beanbean iddatefactory-beansimpleDateFormatfactory-methodparseconstructor-arg namesourcevalue2023-08-27 07:20:00//bean2.4 配置MyBatis的SqlSessionFactory导入MyBatis的相关坐标!--mybatis框架--dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.5/version/dependency!--mysql驱动--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.49/version/dependencyMyBatis原始获得SqlSessionFactory的方式//加载mybatis核心配置文件使用Spring静态工厂方式InputStreaminResources.getResourceAsStream(“mybatis-conifg.xml”);//创建SqlSessionFactoryBuilder对象使用Spring无参构造方式SqlSessionFactoryBuilderbuildernewSqlSessionFactoryBuilder();//调用SqlSessionFactoryBuilder的build方法使用Spring实例工厂方式SqlSessionFactorysqlSessionFactorybuilder.build(in);SqlSessionFactory交由Spring管理配置如下!--静态工厂方式产生Bean实例--bean id“inputStream”class“org.apache.ibatis.io.Resources” factory-method“getResourceAsStream”constructor-arg name“resource” value“mybatis-config.xml“//bean!--无参构造方式产生Bean实例--bean idsqlSessionFactoryBuilderclassorg.apache.ibatis.session.SqlSessionFactoryBuilder/!--实例工厂方式产生Bean实例--bean idsqlSessionFactoryfactory-beansqlSessionFactoryBuilderfactory-methodbuildconstructor-arg nameinputStreamrefinputStream//bean