在Spring的IOC容器里配置Bean
配置Bean形式:基於xml文件方式、基於注解的方式
在xml文件中通過bean節點配置bean:
<?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 name="helloSpring" class="com.dx.spring.beans.HelloSpring"> <property name="name" value="Spring"></property> </bean> </beans>
參考:《Spring(二):Spring框架&Hello Spring》中配置過程
id:Bean的名稱
1)在IOC容器中必須是唯一的;
2)若id沒有指定,Spring會自動將全系nag定型為類名作為Bean的名字;
3)id可以指定多個名字,名字之間可用逗號、分號、或空格分隔。
Bean的配置方式:
1)通過全類名(反射實現,此時要求該bean類擁有一個無參數構造器)、
2)通過工廠方法(靜態工廠方法&實例工廠方法,參考:《Spring(十三):使用工廠方法來配置Bean的兩種方式(靜態工廠方法&實例工廠方法)》)、
3)FactoryBean(參考:《Spring(十四):使用FactoryBean配置Bean》)
4)@Configuration注解的配置類中注冊bean,具體如下:
package test; public class User { private Integer id; private String name; 。。。 } // 定義配置Bean配置類 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ApplicationConfigBean { @Bean public User getUser() { return new User(); } } // 測試類 import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class App { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfigBean.class); System.out.println(ctx.getBean(User.class)); } }
IOC容器BeanFactory&ApplicationContext概述
Spring容器
1)在Spring IOC容器讀取Bean配置創建Bean實例之前,必須對它進行實例化。只有在容器實例化后,才可以從IOC容器里獲取Bean實例並使用。
2)Spring提供了兩種類型IOC容器實現
---BeanFactory:IOC容器的基本實現。BeanFactory是Spring框架的基礎設施,面向Spring本身。
---ApplicationContext:提供了更多的高級屬性,是BeanFactory的子接口。ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext,而非底層的BeanFactory。
備注:
1)無論使用兩種方式的哪一種,配置文件是相同的。
2)如何卻別ApplicatinContext是BeanFactory的子接口:
ApplicatinContext的類定義:
// Compiled from ApplicationContext.java (version 1.8 : 52.0, no super bit) public abstract interface org.springframework.context.ApplicationContext
extends org.springframework.core.env.EnvironmentCapable,
org.springframework.beans.factory.ListableBeanFactory,
org.springframework.beans.factory.HierarchicalBeanFactory,
org.springframework.context.MessageSource,
org.springframework.context.ApplicationEventPublisher,
org.springframework.core.io.support.ResourcePatternResolver { // Method descriptor #10 ()Ljava/lang/String; @org.springframework.lang.Nullable public abstract java.lang.String getId(); // Method descriptor #10 ()Ljava/lang/String; public abstract java.lang.String getApplicationName(); // Method descriptor #10 ()Ljava/lang/String; public abstract java.lang.String getDisplayName(); // Method descriptor #16 ()J public abstract long getStartupDate(); // Method descriptor #18 ()Lorg/springframework/context/ApplicationContext; @org.springframework.lang.Nullable public abstract org.springframework.context.ApplicationContext getParent(); // Method descriptor #20 ()Lorg/springframework/beans/factory/config/AutowireCapableBeanFactory; public abstract org.springframework.beans.factory.config.AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws java.lang.IllegalStateException; }
從上邊我們知道ApplicationContext是繼承了org.springframework.beans.factory.ListableBeanFactory,org.springframework.beans.factory.HierarchicalBeanFactory接口,而這兩個接口都是繼承了org.springframework.beans.factory.BeanFactory接口。
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
因此,說ApplicationContext是BeanFactory的子接口類。
ApplicaionContext
ApplicationContext的主要實現類:
---ClassPathXmlApplicationContext:從類路徑下加載配置文件
---FileSystemXmlApplicationContext:從文件系統中加載配置文件。
ConfigurableApplicationContext擴展與ApplicationContext,新增加兩個主要的方法:refresh()和close(),讓ApplicationContext具有啟動、刷新和關閉上下文的能力。
// Compiled from ConfigurableApplicationContext.java (version 1.8 : 52.0, no super bit) public abstract interface org.springframework.context.ConfigurableApplicationContext extends org.springframework.context.ApplicationContext, org.springframework.context.Lifecycle, java.io.Closeable { // Field descriptor #8 Ljava/lang/String; public static final java.lang.String CONFIG_LOCATION_DELIMITERS = ",; \t\n"; // Field descriptor #8 Ljava/lang/String; public static final java.lang.String CONVERSION_SERVICE_BEAN_NAME = "conversionService"; // Field descriptor #8 Ljava/lang/String; public static final java.lang.String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver"; // Field descriptor #8 Ljava/lang/String; public static final java.lang.String ENVIRONMENT_BEAN_NAME = "environment"; // Field descriptor #8 Ljava/lang/String; public static final java.lang.String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties"; // Field descriptor #8 Ljava/lang/String; public static final java.lang.String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment"; // Method descriptor #22 (Ljava/lang/String;)V public abstract void setId(java.lang.String arg0); // Method descriptor #24 (Lorg/springframework/context/ApplicationContext;)V public abstract void setParent(@org.springframework.lang.Nullable org.springframework.context.ApplicationContext arg0); // Method descriptor #28 (Lorg/springframework/core/env/ConfigurableEnvironment;)V public abstract void setEnvironment(org.springframework.core.env.ConfigurableEnvironment arg0); // Method descriptor #30 ()Lorg/springframework/core/env/ConfigurableEnvironment; public abstract org.springframework.core.env.ConfigurableEnvironment getEnvironment(); // Method descriptor #32 (Lorg/springframework/beans/factory/config/BeanFactoryPostProcessor;)V public abstract void addBeanFactoryPostProcessor(org.springframework.beans.factory.config.BeanFactoryPostProcessor arg0); // Method descriptor #34 (Lorg/springframework/context/ApplicationListener;)V // Signature: (Lorg/springframework/context/ApplicationListener<*>;)V public abstract void addApplicationListener(org.springframework.context.ApplicationListener arg0); // Method descriptor #38 (Lorg/springframework/core/io/ProtocolResolver;)V public abstract void addProtocolResolver(org.springframework.core.io.ProtocolResolver arg0); // Method descriptor #40 ()V public abstract void refresh() throws org.springframework.beans.BeansException, java.lang.IllegalStateException; // Method descriptor #40 ()V public abstract void registerShutdownHook(); // Method descriptor #40 ()V public abstract void close(); // Method descriptor #47 ()Z public abstract boolean isActive(); // Method descriptor #49 ()Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory; public abstract org.springframework.beans.factory.config.ConfigurableListableBeanFactory getBeanFactory() throws java.lang.IllegalStateException; // Method descriptor #50 ()Lorg/springframework/core/env/Environment; // Stack: 1, Locals: 1 public bridge synthetic org.springframework.core.env.Environment getEnvironment(); 0 aload_0 [this] 1 invokeinterface org.springframework.context.ConfigurableApplicationContext.getEnvironment() : org.springframework.core.env.ConfigurableEnvironment [1] [nargs: 1] 6 areturn Line numbers: [pc: 0, line: 43] Local variable table: [pc: 0, pc: 7] local: this index: 0 type: org.springframework.context.ConfigurableApplicationContext }
ApplicationContext在初始化上下文時就實例化所有單例的Bean。
WebApplicationContext是專門為WEB應用而准備的,它允許從相對於WEB根目錄的路徑中完成初始化工作。
依賴注入的方式:
1)屬性注入(set方法注入);
package com.dx.spring.beans; public class HelloSpring { private String name; public HelloSpring() { } public void setName(String name) { this.name = name; } public void sayHello() { System.out.println("Hello " + this.name); } }
setName方法注入:
<bean name="helloSpring" class="com.dx.spring.beans.HelloSpring"> <property name="name" value="Spring"></property> </bean>
2)構造函數注入;
a)通過構造方法注入Bean的屬性值或依賴的對象,它保證了Bean實例在實例化后就可以使用。
b)構造器注入在<constructor-arg>元素里聲明屬性,<constructor-arg>中沒有name屬性。
<bean name="car" class="com.dx.spring.beans.Car"> <constructor-arg value="AUDI" index="0"></constructor-arg> <constructor-arg value="Shanghai" index="1"></constructor-arg> <constructor-arg value="400000" type="double"></constructor-arg> </bean> <bean name="car2" class="com.dx.spring.beans.Car"> <constructor-arg value="BMW" type="java.lang.String"></constructor-arg> <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg> <constructor-arg value="260" type="int"></constructor-arg> </bean>
Car.java
package com.dx.spring.beans; public class Car { private String brand; private String corp; private double price; private int maxSpeed; public Car(String brand, String corp, double price) { super(); this.brand = brand; this.corp = corp; this.price = price; } public Car(String brand, String corp, int maxSpeed) { super(); this.brand = brand; this.corp = corp; this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + ", maxSpeed=" + maxSpeed + "]"; } }
client.java
public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring"); Car car = (Car) applicationContext.getBean("car"); Car car2 = (Car) applicationContext.getBean("car2"); System.out.println(car); System.out.println(car2); }
輸出信息:
Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=0] Car [brand=BMW, corp=Shanghai, price=0.0, maxSpeed=260]
3)工廠方法注入
不推薦、也不常用
注入屬性值細節
1)字面值
字面值:可用字符串表示的值,可以通過<value>元素標簽或value屬性進行注入。
基本數據類型及封裝類、String等類型都可以采用字面值注入的方式
若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起來。
Person.java

package com.dx.spring.beans; public class Person { private String name; private String age; private Car car; public Person(String name, String age, Car car) { super(); this.name = name; this.age = age; this.car = car; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } }
<bean name="car2" class="com.dx.spring.beans.Car"> <constructor-arg value="BMW" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><![CDATA[<Shanghai>]]></value> </constructor-arg> <constructor-arg type="int"> <value>260</value> </constructor-arg> </bean>
2)引用其它Bean
組成應用程序的Bean機場需要相互協作已完成應用程序的功能,需要使用Bean能夠相互訪問,就必須在Bean配置文件中指定對Bean的引用
在Bean的配置文件中,可以通過<ref>元素或者ref屬性為bean的屬性或,構造器參數指定對bean的引用。
也可以在屬性或構造器里包含Bean的聲明,這樣的Bean成為內部Bean。
3)注入參數詳解:null值和級聯屬性
可以使用專用的<null/>元素標簽為bean的字符串或其它對象類型的屬性注入null值。
<bean id="person3" class="com.dx.spring.beans.Person"> <constructor-arg value="Lisi"></constructor-arg> <constructor-arg value="25"></constructor-arg> <constructor-arg name="car"> <null/> </constructor-arg> </bean>
和struts、hibernate等框架一樣,spring支持級聯屬性的配置。
<bean id="person" class="com.dx.spring.beans.Person"> <constructor-arg value="Zhangsan"></constructor-arg> <constructor-arg value="24"></constructor-arg> <constructor-arg ref="car"></constructor-arg> <property name="car.maxSpeed" value="260"></property> </bean>
注意:
1)上邊代碼必須要要求先初始化car,否則直接給car.maxSpeed賦值會拋出異常與struts2不同點。
2)需要在car中實現setMaxSpeed方法。
public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; }
4)集合屬性
在Spring中可以通過一組內置的xml標簽(例如:<list>,<set>,<map>)來配置集合屬性。
4.1)配置java.util.List類型的屬性,需要指定<list>標簽,在標簽里包含一些元素。這些標簽可以通過<value>指定簡單的常量值,通過<ref>指定對其它Bean的引用,通過<bean>指定內置bean定義。通過<null/>指定空元素。甚至可以內嵌其他集合。
applicationContext.xml
<bean name="car" class="com.dx.spring.beans.Car"> <constructor-arg value="AUDI" index="0"></constructor-arg> <constructor-arg value="Shanghai" index="1"></constructor-arg> <constructor-arg value="400000" type="double"></constructor-arg> </bean> <bean name="car2" class="com.dx.spring.beans.Car"> <constructor-arg value="BMW" type="java.lang.String"></constructor-arg> <constructor-arg type="java.lang.String"> <value><![CDATA[<Shanghai>]]></value> </constructor-arg> <constructor-arg type="int"> <value>260</value> </constructor-arg> </bean> <bean id="person4" class="com.dx.spring.beans.collections.Person"> <property name="name" value="Nike"></property> <property name="age" value="25"></property> <property name="cars"> <list> <ref bean="car" /> <ref bean="car2" /> </list> </property> </bean>
client.java
public static void main(String[] args) { ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = (Person) cxt.getBean("person4"); System.out.println(person); }
Person.java

package com.dx.spring.beans.collections; import java.util.List; import com.dx.spring.beans.Car; public class Person { private String name; private int age; private List<Car> cars; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", cars=" + cars + "]"; } }
打印結果:
Person [name=Nike, age=25, cars=[Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=260], Car [brand=BMW, corp=<Shanghai>, price=0.0, maxSpeed=260]]]
4.2)數組的定義和List一樣,都可以使用<list>
修改Person.java為:
public Car[] getCars() { return cars; } public void setCars(Car[] cars) { this.cars = cars; } @Override public String toString() { String carsStr = ""; for (Car car : cars) carsStr += car.toString() + ","; return "Person [name=" + name + ", age=" + age + ", cars=[" + carsStr + "]]"; }
applicationContext.xml不變,client.java也不變,打印結果:
Person [name=Nike, age=25, cars=[Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=260],Car [brand=BMW, corp=<Shanghai>, price=0.0, maxSpeed=260],]]
4.3)配置java.util.Set需要使用<set>標簽,定義元素的方法與List一樣。
修改Person.car屬性類型:
private Set<Car> cars; public Set<Car> getCars() { return cars; } public void setCars(Set<Car> cars) { this.cars = cars; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", cars=" + cars+ "]"; }
修改applicationContext.xml
<bean id="person4" class="com.dx.spring.beans.collections.Person"> <property name="name" value="Nike"></property> <property name="age" value="25"></property> <property name="cars"> <set> <ref bean="car" /> <ref bean="car2" /> </set> </property> </bean>
client.java不變,打印結果:
Person [name=Nike, age=25, cars=[Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=260], Car [brand=BMW, corp=<Shanghai>, price=0.0, maxSpeed=260]]]
4.4)java.util.Map通過<map>標簽定義,<map>標簽里可以使用多個<entry>作為子標簽,每個條目包含一個鍵和一個值。
4.4.1)map必須在<key>標簽里定義鍵。
4.4.2)因為鍵和值的類型沒有限制,所以可以自由地為它們指定<value>,<ref>,<bean>或<null>元素。
4.4.3)可以將Map的鍵和值作為<entry>的屬性定義:簡單常量可以使用key和value來定義;Bean引用通過key-ref和value-ref屬性定義。
修改Person.car屬性類型:
private Map<String,Car> cars; public Map<String,Car> getCars() { return cars; } public void setCars(Map<String,Car> cars) { this.cars = cars; }
修改applicationContext.xml
<bean id="person4" class="com.dx.spring.beans.collections.Person"> <property name="name" value="Nike"></property> <property name="age" value="25"></property> <property name="cars"> <map> <entry key="car1" value-ref="car"></entry> <entry key="car2" value-ref="car2"></entry> </map> </property> </bean>
client.java不變,打印結果為:
Person [name=Nike, age=25, cars={car1=Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=260], car2=Car [brand=BMW, corp=<Shanghai>, price=0.0, maxSpeed=260]}]
5)使用<props>定義java.util.Properties,該標簽使用多個<prop>作為子標簽,每個<prop>標簽必須定義key屬性。
定義DataSource.java
package com.dx.spring.beans.collections; import java.util.Properties; public class DataSource { private Properties properties; public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "DataSource [properties=" + properties + "]"; } }
applicationContext.xml配置:
<bean id="proerpties_test" class="com.dx.spring.beans.collections.DataSource"> <property name="properties"> <props> <prop key="username">username</prop> <prop key="password">password</prop> <prop key="jdbcUri">jdbc:mysql:3306///test</prop> <prop key="driverClass">com.mysql.jdbc.Driver</prop> </props> </property> </bean>
client.java
public static void main(String[] args) { ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource=(DataSource)cxt.getBean("proerpties_test"); System.out.println(dataSource); }
打印結果:
DataSource [properties={jdbcUri=jdbc:mysql:3306///test, driverClass=com.mysql.jdbc.Driver, password=password, username=username}]
5)使用utility schema 定義集合
5.1)之前使用基本的集合標簽定義集合是,不能將集合作為獨立的Bean定義,導致其他Bean無法引用該集合,所以無法在不同的Bean之間共享集合。
5.2)可以使用util schema 里的集合標簽定義獨立的集合Bean。需要注意的是,必須在<beans>根元素里添加util schema定義。
舉例:
Person.java

package com.dx.spring.beans.collections; import java.util.List; import com.dx.spring.beans.Car; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } private List<Car> cars; public List<Car> getCars() { return cars; } public void setCars(List<Car> cars) { this.cars = cars; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", cars=" + cars+ "]"; } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <bean id="person4" class="com.dx.spring.beans.collections.Person"> <property name="name" value="Nike"></property> <property name="age" value="25"></property> <property name="cars" ref="cars"></property> </bean> <util:list id="cars"> <ref bean="car"></ref> <ref bean="car2"></ref> <bean name="car3" class="com.dx.spring.beans.Car"> <constructor-arg value="Ford" index="0"></constructor-arg> <constructor-arg value="Changan" index="1"></constructor-arg> <constructor-arg value="140000" type="double"></constructor-arg> </bean> </util:list> </beans>
測試client.java
public static void main(String[] args) { ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml"); Person person = (Person) cxt.getBean("person4"); System.out.println(person); }
打印結果:
Person [
name=Nike,
age=25,
cars=
[
Car [brand=AUDI, corp=Shanghai, price=400000.0, maxSpeed=260],
Car [brand=BMW, corp=<Shanghai>, price=0.0, maxSpeed=260],
Car [brand=Ford, corp=Changan, price=140000.0, maxSpeed=0]
]
]
6)使用p命名空間
6.1)為了簡化xml文件的配置,原來越多的xml文件采用屬性而非子元素配置信息。
6.2)Spring從2.5版本開始引入了一個新的p命名空間,可以通過<bean>元素屬性的方式配置bean的屬性。
6.3)使用p命名空間后,基於xml的配置方式將進一步簡化。
<bean id="person4" class="com.dx.spring.beans.collections.Person" p:name="Nike" p:age="25" p:cars-ref="cars"> <!-- <property name="name" value="Nike"></property> <property name="age" value="25"></property> <property name="cars" ref="cars"></property> --> </bean> <util:list id="cars"> <ref bean="car"></ref> <ref bean="car2"></ref> <bean name="car3" class="com.dx.spring.beans.Car"> <constructor-arg value="Ford" index="0"></constructor-arg> <constructor-arg value="Changan" index="1"></constructor-arg> <constructor-arg value="140000" type="double"></constructor-arg> </bean> </util:list>