基于xml的Bean的配置
在Spring中,Bean是指被Spring IOC容器管理的Java对象。在配置Bean时,我们可以通过XML配置文件或者注解的方式来告诉Spring容器应该如何创建和管理这些Bean。
- 配置Bean的id和class属性 在XML配置文件中,我们需要使用**<bean>**标签来配置Bean,其中最重要的是id和class属性。id属性用于指定Bean在容器中的名称,而class属性用于指定Bean的实现类。例如:
<bean id="userDao" class="com.congyun.dao.impl.UserDaoImpl">
这段配置的含义是,创建一个名为"userDao"的Bean,并将其实现类指定为"com.congyun.dao.impl.UserDaoImpl"。这样,在Spring容器启动时,就会根据这个配置信息创建一个UserDaoImpl对象,并将其放入Spring容器中
此时存储到Spring容器(singleObjects单例池)中的Bean的beanName是userDao,值是UserDaolmpl对象,可以根据beanName获取Bean实例
applicationContext.getBean ( "userDao" ) ;
如果不配置id,则Spring会把当前Bean实例的全限定名作为beanNa
applicationContext.getBean ( "com.congyun.dao.impl.UserDaoImpl");
- 配置Bean的作用域 在配置Bean时,我们可以通过scope属性来指定Bean的作用域。Spring支持以下5种作用域:
- singleton:单例模式,一个容器只会创建一个Bean实例,默认值,每次getBean时都是从单例池中获取相同的Bean实例。
- prototype:原型模式,每次从容器中获取Bean时都会创建一个新的实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例
- request:请求作用域,每次HTTP请求都会创建一个新的Bean实例
- session:会话作用域,每个HTTP会话都会创建一个新的Bean实例
- 上述两组需要导入spring-webmvc
- global session:全局会话作用域,通常用于Portlet应用中
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" scope="prototype">
这样,每次从Spring容器中获取userService时,都会创建一个新的UserServiceImpl对象。
-
配置Bean的依赖关系 在Spring中,Bean之间可以存在依赖关系,即一个Bean依赖于另一个Bean。在配置Bean时,我们可以使用**<property>**标签或者构造函数注入的方式来定义Bean之间的依赖关系
-
使用<property>标签注入依赖 使用<property>标签注入依赖时,需要指定name属性和ref属性。其中name属性指定要注入的属性名称,ref属性指定要注入的Bean的id或者名称。
例如,将userService中的userDao属性注入userDao Bean:
<bean id="userService" class="com.congyun.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean>
-
使用构造函数注入依赖 使用构造函数注入依赖时,需要在标签中使用标签来指定构造函数参数的值或者Bean的引用。
例如,将userService中的userDao属性通过构造函数注入:
public class UserService { private UserDao userDao; public UserService(UserDao userDao) { this.userDao = userDao; } } <bean id="userDao" class="com.congyun.dao.impl.UserDaoImpl" /> <bean id="userService" class="com.congyun.service.impl.UserServiceImpl"> <constructor-arg ref="userDao" /> </bean>
-
-
Bean的别名配置:可以为当前Bean指定多个别名,根据别名也可以获得Bean对象
<bean id="userDao" name="aaa,bbb" class=" com.congyun.dao.impl.UserDaoImpl"/>
此时多个名称都可以获得UserDaolmpl实例对象
applicationContext.getBean("userDao"); applicationContext.getBean("aaa"); applicationContext.getBean ("bbb");
-
Bean的延迟加载
当lazy-initi设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的<bean id="userDao" class=" com.congyun.dao.impl.UserDaoImpl" lazy-init="true" />
-
Bean的初始化和销毁方法配置
Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作
Bean在销毁之前也可以执行指定的销毁
方法完成一些操作,初始化方法名称和销毁方法名称通过<bean id="userDao" class="com.congyun.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy" / >
public class UserDaoImpl implements UserDao { public UserDaoImpl() { System.out.println ( "UserDaoImpl创建了..."); } public void init(){ System.out.println ("初始化方法..."); } public void destroy(){ System.out.println("销毁方法..."); } } // 销毁函数的执行 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); // 根据beanName获得容器中的Bean实例 UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService); UserService userService1 = (UserService) applicationContext.getBean("service"); System.out.println(userService1); applicationContext.close();
当一个Bean的作用域为prototype时,容器不会管理该Bean的生命周期,也就是不会调用该Bean的销毁方法(destroy-method)
如果需要在一个prototype作用域的Bean销毁时执行特定的逻辑,可以通过在该Bean的使用方手动调用销毁方法来实现。比如在使用该Bean的方法或者类中,在不需要该Bean实例时手动调用销毁方法。
另外,需要注意的是,对于prototype作用域的Bean,Spring容器只会在创建该Bean实例时执行一次init-method方法,而不会在每次获取Bean实例时都执行。因此,在prototype作用域下,init-method方法只会在Bean实例创建时执行一次,而destroy-method方法则需要手动调用。
扩展:除此之外,我们还可以通过实现 InitializingBean接口,完成一些Bean的初始化操作,如下:
public class UserDaoImpl implements UserDao,InitializingBean { public UserDaoImpl () { System.out.println ( "UserDaoImpl创建了..."); } public void init () { System.out.println("初始化方法..." ); } public void destroy () { System.out.println("销毁方法..."); }//执行时机早于init-method配置的方法 public void afterPropertiesSet ( ) throws Exception { System.out.println ( " InitializingBean. . . " ) ; } // PS:afterPropertiesSet和初始化方法均需要在实例的属性值设置完之后才去执行
-
Bean的实例化配置
Spring的实例化方式主要如下两种:- 构造方式实例化:底层通过构造方法对Bean进行实例化
<bean id="userService" class="com.congyun.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy" scope="prototype" name="service"> <!--依赖注入--> <constructor-arg name="name" value="congyun"></constructor-arg> <property name="userDao" ref="userDao"/> </bean> 在写了<constructor-arg name="name" value="congyun"></constructor-arg>后自动执行有参构造,去掉则执行无参构造
-
工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
- 静态工厂方法实例化Bean——通过这种方法可以在Bean创建之间执行一些其他的逻辑操作
@Test // Static factory public void staticFactory(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userServiceOne"); System.out.println(userService); } package com.congyun.factory; import com.congyun.service.UserService; import com.congyun.service.impl.UserServiceImpl; public class staticFactory { public static UserService userService(){ return new UserServiceImpl(); } } <bean id="userServiceOne" class="com.congyun.factory.staticFactory" factory-method="userService"> </bean>
- 实例工厂方法实例化Bean——通过这种方法可以在Bean创建之间执行一些其他的逻辑操作
@Test // beanUserService public void beanUserService(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("beanUserService"); System.out.println(userService); } public class beanFactory { public UserService userService(){ return new UserServiceImpl(); } }
<bean id="beanFactory" class="com.congyun.factory.beanFactory"> </bean> <bean id="beanUserService" factory-bean="beanFactory" factory-method="userService" scope="prototype"> </bean>
- 实现FactoryBean规范延迟实例化Bean
@Test public void factoryBean(){ ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) app.getBean("factoryBean"); UserService userService1 = (UserService) app.getBean("factoryBean"); System.out.println(userService); System.out.println(userService1); // 两者输出结果一直的原因:均是从FactoryBeanObjectCache中获取的数据,当设置为prototype,FactoryBeanObjectCache的值为NULL } public class beanFactory { public UserService userService(){ return new UserServiceImpl(); } } <bean id="factoryBean" class="com.congyun.factory.factoryBean"> </bean>
-
bean的注入方式
注入方式 配置方式 通过Bean的set方法注入 <property name=“userDao” ref=“userDao” />
<property name=“userDao” value=“haohao”/>通过构造Bean的方法进行注入 <constructor-arg name=“name” ref=“userDao”/>
<constructor-arg name=“name” value=“haohao”/>依赖注入的数据类型有如下三种:
- 普通数据类型,例如: String.int、boolean等,通过value属性指定
- 引用数据类型,例如: UserDaolmpl、DataSource等,通过ref属性指定
- 集合数据类型,例如:List、Map、Properties等
@Test public void ListTest(){ ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) app.getBean("userService"); System.out.println(userService); } public class UserServiceImpl implements UserService { List<String> myString; public void setMyString(List<String> myString) { this.myString = myString; getMyString(); } public List<String> getMyString() { for (int i =0; i < myString.size();i++) System.out.println(myString.get(i)); return myString; } public List<UserDaoImpl> setUserDao(List<UserDaoImpl> userDao) { this.userDao = userDao; return userDao; } } <!--配置UserServiceImpl--> <bean id="userService" class="com.congyun.service.impl.UserServiceImpl"> <property name="myString"> <list> <value>test</value> <value>test1</value> <value>test2</value> <value>test3</value> </list> </property> <property name="userDao"> <list> <ref bean="userDao"></ref> <ref bean="userDao"></ref> <ref bean="userDao"></ref> // 在外部创建多个不同的userDao </list> </property> </bean>
自动装配:如果被注入的属性类型是Bean引用的话,那么可以在**<bean>标签中使用autowire属性去配置自动注入方式**,属性值有两个:
- byName:通过属性名自动装配,即去匹配 setXxx 与id=“xxx” (name=“xxx”)是否一致
- byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错。
<bean id="userService" class="com.itheima.service.imp1.UserServiceImpl"autowire="byType">
-
Spring的其他配置标签
Spring的xml标签大体上分为两类,一种是默认标签,一种是自定义标签
- 默认标签:就是不用额外导入其他命名空间约束的标签,例如<bean>标签
- 自定义标签:就是需要额外引入其他命名空间约束,并通过前缀引用的标签,例如**<context.property-placeholder/>**标签
标签 作用 <beans> 一般作为xml配置根标签,其他标签都是该标签的子标签 <bean> Bean的配置标签,上面已经详解了,此处不再阐述 <import> 外部资源导入标签 <alias> 指定Bean的别名标签,使用较少 <beans>标签,除了经常用的做为根标签外,还可以嵌套在根标签内,使用profile属性切换开发环境
<bean></bean> <!-―配置测试环境下,需要加载的Bean实例--> <beans profi1c="test"> </beans> <!-―配置开发环境下,需要加载的Bean实例--> <beans profi1e="dev" > </beans>
可以使用以下两种方式指定被激活的环境:
- 使用命令行动态参数,虚拟机参数位置加载**-Dspring.profiles.active=test**
- 使用代码的方式设置环境变量:在执行相关代码之前添加System.setProperty(“spring.profiles.active” ,“test”)
此时公共部分的bean和指定激活的环境生效
**<import>**标签,用于导入其他配置文件,项目变大后,项目变大后,就会导致一个配置文件内容过多,可以将一个配置文件根据业务某块进行拆分,拆分后,最终通过<import>标签导入到一个主配置文件中,项目加载主配置文件就连同导入的文件一并加载了
<!--导入用户模块配置文件--> <import resource="classpath:UserModuleApplicationcontext.xml"/> <!--导入商品模块配置文件--> <import resource="classpath:ProductModuleApplicationcontext.xml" />
Spring的自定义标签需要引入外部的命名空间,并为外部的命名空间指定前缀,使用**<前缀:标签>**形式的标签,称之为自定义标签,自定义标签的解析流程也是Spring xml扩展点方式之一
// 这个部分的内容根据标签名称自己在网上查找 xmlns:mvc="http://www.springframework.org/schema/mvc" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--默认标签--> <bean id="userDao" class="com.congyun.dao.imp1.UserDaoImpl" /> <!--自定义标签--> <context:property-placeholder/> <mvc:annotation-driven/> <dubbo:application name="application"/>
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 autowire=“byType”> | 设置自动注入模式,常用的有按照类型byType,按照名字byName |
<bean factory-bean=“” factory-method=“”/> | 指定哪个工厂Bean的哪个方法完成Bean的创建 |