Spring——装配Bean 我不是女神ヾ 2022-05-28 22:44 209阅读 0赞 ## **基本装配** ## 在Spring容器内拼凑Bean叫做装配。装配Bean的时候,需要告诉哪些Bean以及容器如何使用依赖注入将它们配合在一起。 ### **使用XML装配** ### XML是最常见的Spring应用系统配置源。 几种Spring容器都支持使用XML装配Bean,包括: 1. XmlBeanFactory:调用ClassPathResource载入上下文定义文件(比如applicationContext.xml)。 2. ClassPathXmlApplicationContext:从类路径载入上下文定义文件。 3. XmlWebApplicationContext:从Web应用上下文中载入定义文件。 配置文件举例如下: <?xml version="1.0" encoding="UTF-8"?> <beans 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 id="student" class="com.gavin.ioc.Student" scope="singleton"> <property name="name" value="Gavin"/> </bean> </beans> * 上下文定义文件的根元素是beans,有多个bean子元素。每个bean元素定义了一个bean如何被装配到Spring容器中。 * 对bean的最基本的配置包括bean的ID和bean的全称类名。 ### **scope** ### 几种scope属性值:`prototype`、`singleton`、`request`、`session`、`global-session`。Spring中的bean缺省情况下是单例模式。始终返回一个实例。若想返回不同的实例的话需要定义成原型模式。 <table> <thead> <tr> <th>作用域</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td>singleton</td> <td>在每个Spring IoC 容器中一个Bean定义对应一个对象实例</td> </tr> <tr> <td>prototype</td> <td>一个Bean定义对应多个实例</td> </tr> <tr> <td>request</td> <td>在一个HTTP请求中,一个Bean定义对应一个对象实例;即每次HTTP请求都将会有各自的Bean实例,它们依据某个Bean定义创建而成。该作用域仅在基于Web的Spring Application情形下有效。</td> </tr> <tr> <td>session</td> <td>在一个HTTP Session中,一个Bean定义对应一个对象实例。该作用域仅在基于Web的Spring Application情形下有效。</td> </tr> <tr> <td>global-session</td> <td>在一个全局的HTTP Session中,一个Bean定义对应一个对象实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于Web的Spring Application情形下有效。</td> </tr> </tbody> </table> 使用原型Bean会对性能产生影响,尽量不要设置为prototype,除非有必要。 ### **实例化与销毁** ### Spring实例化bean或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法,即`init-method`方法和`destory-method`方法 -------------------- Spring也提供了两个接口来实现相同的功能:`InitializingBean`和`DisposableBean`。`InitializingBean`接口提供了一个`afterPropertiesSet()`方法。`DisposableBean`接口提供了`destroy()`方法。 但是不推荐使用这两个接口,它会把Bean与Spring API绑定在一起。 ## **通过set方法注入依赖** ## bean元素的property子元素指明了使用它们的set方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的Bean。 ### **内部Bean** ### 在property内部配置一个Bean,那么这个Bean只能被该属性引用。而不能被其他属性引用。 <bean id="outside" class="..."> <property name="emp"> <bean id="inside" class="..."> <property name="" value=""/> </bean> </property> </bean> 如上例所示,emp属性引用inside这个Bean,这里inside这个Bean只能被该emp属性引用,其他属性是不能引用的。 ### **继承配置** ### Graduate类继承Student类,属性如下: public class Student { protected int age; protected String name; ... } public class Graduate extends Student { private String degree; ... } 配置如下: <!--配置一个学生--> <bean id="student" class="com.gavin.inherit.Student"> <property name="age" value="18"/> <property name="name" value="Gavin"/> </bean> <bean id="graduate" parent="student" class="com.gavin.inherit.Graduate"> <!--如果单独再配置name和age,则会覆盖从父对象继承的这个属性的值--> <property name="age" value="20"/> <property name="name" value="XiaoMing"/> <property name="degree" value="学士"/> </bean> ### **给集合属性注入值** ### 给数组或List集合注入值的配置方式如下: Department有三个属性: private String name; private String[] empName; private List employeeList; <property name="empName"> <list> <value>小明</value> <value>小红</value> <value>小亮</value> </list> </property> <property name="employeeList"> <list> <ref bean="employee"/> <ref bean="employee1"/> <ref bean="employee2"/> </list> </property> 给Set集合的注入与此类似: <property name="employeeSet"> <set> <ref bean="employee"/> <ref bean="employee1"/> <ref bean="employee2"/> <ref bean="employee2"/> <ref bean="employee2"/> </set> </property> ### **给Map属性注入值** ### Map的注入也是类似的,不过稍有复杂而已: Department中增加Map属性: private Map employeeMap; Spring中配置如下: <property name="employeeMap"> <map> <entry key="1" value-ref="employee"/> <entry key="2" value-ref="employee1"/> <entry key="3" value-ref="employee2"/> </map> </property> ### **注入空值** ### <property name="barlist"> <null/> </property> ## **通过构造函数注入依赖** ## Employee对象如下: public class Employee { private String name; private int age; public Employee() { } public Employee(String name, int age) { System.out.println("Employee(String name, int age)函数被调用"); this.name = name; this.age = age; } public Employee(String name) { System.out.println("Employee(String name)函数被调用"); this.name = name; } } 配置文件: <beans 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"> <!--配置一个Employee对象--> <bean id="employee" class="com.gavin.constructor.Employee"> <!--通过构造函数来注入--> <constructor-arg index="0" value="Gavin"/> <constructor-arg index="1" value="19"/> </bean> </beans> 也就是说,可以通过在bean元素下,配置constructor-arg元素来给构造函数传递参数。index用于指定参数的位置。 > **set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不可能实例化不完全的或无法使用的Bean。** > > **如果属性是对象类型,则使用ref=”“** ## **自动装配Bean的属性值** ## <bean id="foo" class="...Foo" autowire="autowire type"> 有四种自动装配类型: 1. byName:寻找和属性名相同的Bean,若找不到,则装不上。 2. byType:寻找和属性类型相同的Bean,找不到,装不上,找到多个抛异常 3. constructor:查找和bean的构造参数一致的一个或多个Bean,若找不到或找到多个,抛异常。按照参数的类型匹配。 4. autodetect:(3)和(2)之间选一个方式。不确定性的处理与(3)和(2)一致。【3和2有先后顺序!】 5. default:这个需要在beans中配置`default-autowire="指定"`。当在beans中指定了default-autowired之后,所有Bean的默认autowire方式就是该指定的装配方式。 6. no:不自动装配,这是autowire的默认值 * **byName的案例:** public class Dog { private String name; private int age; ... } public class Master { private String name; private Dog dog; ... } Master中有Dog对象,配置如下: <beans 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"> <!--Master对象--> <bean id="master" class="com.gavin.autowire.Master" autowire="byName"> <property name="name" value="Gavin"/> </bean> <!--Dog对象--> <bean id="dog" class="com.gavin.autowire.Dog"> <property name="name" value="大黄"/> <property name="age" value="2"/> </bean> </beans> 可以看到,master中并没有引用dog对象,而是设置了属性autowire=byName,这时Spring容器会根据属性名字寻找,找到属性名是dog的对象后,自动装配。 其他的也类似,比如byType是按照类型来寻找,那么不管Dog对象的属性名是什么,只要能找到一个Dog对象,就能自动装配。但是找到多个Dog对象就会抛出异常了。 * constructor的话,需要在Master中写一个只有Dog参数的构造方法,那么Spring容器会将配置的Dog对象传递给这个构造函数。 public class Master { private String name; private Dog dog; public Master(Dog dog){ this.dog = dog; } ... } 配置如下: <bean id="master" class="com.gavin.autowire.Master" autowire="constructor"> <property name="name" value="Gavin"/> </bean> <!--Dog对象--> <bean id="dog" class="com.gavin.autowire.Dog"> <property name="name" value="大黄"/> <property name="age" value="2"/> </bean> -------------------- **【注意】:自动装配能不用就不用!因为自动装配没有set注入或者构造函数注入明确。** ## **使用Spring特殊的Bean** ## 让Spring特殊对待这些Bean,使它们可以: 1.通过配置后加工Bean,涉及到Bean和Bean工厂生命周期。(比如BeanPostProcessor等) 2.改变依赖注入,将字符串转换成其它类型 3.从属性文本装载信息,包括信息国际化 4.监听并处理其它Bean及Spring发布的系统消息 5.知道自己在Spring中的唯一标识。
还没有评论,来说两句吧...