要使應用程序中的Spring容器成功啓動,需要同時具備以下三方面的條件:
- Spring框架的類包都已經放到應用程序的類路徑下。
- 應用程序爲Spring提供了完備的Bean配置信息。
- Bean的類都已經放到應用程序的類路徑下。
Spring啓動時讀取應用程序提供的Bean配置信息,並在Spring容器中生成一份相應的Bean配置註冊表,然後根據這張註冊表實例化Bean,裝配好Bean之間的依賴關係,爲上層應用提供準備就緒的運行環境。
Bean配置信息是Bean的元數據信息,它由以下四個方面組成:
- bean的實現類
- Bean的屬性信息,如數據源的連接數、用戶名、密碼等。
- Bean的依賴關係,Spring根據依賴關係配置完成Bean之間的裝配。
- Bean的行爲配置,如生命週期範圍及生命週期各過程的回調函數等。
Bean元數據信息在Spring容器中的內部對應物是由一個個BeanDefinition形成的Bean註冊表,Spring實現了Bean元數據信息內部表示和外部定義的解耦。Spring支持多種形式的Bean配置方式。基於Xml、註解、JAva類的配置。
1.基於XML的配置
裝配一個Bean
Car實體:
package com.yf;
public class Car {
private int maxSpeed;
public String brand;
private double price;
@Override
public String toString() {
return "Car [maxSpeed=" + maxSpeed + ", brand=" + brand + ", price=" + price + "]";
}
}
beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="car" class="com.yf.Car">
</bean>
</beans>
main:
package com.yf;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 第一個Spring實例main
*
* @author yf
*
*/
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Car car = (Car) context.getBean("car");
System.out.println(car);
}
}
1.1依賴注入
1.1.1屬性注入:
要求Bean提供一個默認構造函數,併爲需要注入屬性提供相應的Setter方法,Spring先通過默認的構造函數實例化Bean對象,然後通過反射的方式調用setter方法注入屬性值。
Car:默認構造函數和setter方法
package com.yf;
public class Car {
private int maxSpeed;
public String brand;
private double price;
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [maxSpeed=" + maxSpeed + ", brand=" + brand + ", price=" + price + "]";
}
}
屬性配置片段:
<bean id="car" class="com.yf.Car">
<property name="maxSpeed"><value>200</value></property>
<property name="brand"><value>CA72</value></property>
<property name="price"><value>20000.00</value></property>
</bean>
測試main:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Car car = (Car) context.getBean("car");
System.out.println(car);
}
}
運行結果:
Car [maxSpeed=200, brand=CA72, price=20000.0]
1.1.2構造函數注入
Bean必須提供帶參數的構造函數:
Car:
public class Car {
public String brand;
private double price;
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
@Override
public String toString() {
return "Car [ brand=" + brand + ", price=" + price + "]";
}
}
配置:
<bean id="car1" class="com.yf.Car">
<constructor-arg index="0" type="java.lang.String">
<value>CA72</value>
</constructor-arg>
<constructor-arg index="1" type="double">
<value>20000</value>
</constructor-arg>
</bean>
main:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Car car = (Car) context.getBean("car1");
System.out.println(car);
}
}
結果:
Car [ brand=CA72, price=20000.0]
2.基於註解的配置
使用註解定義Bean
//通過Repository定義一個DAO的Bean
@Component("userDao")
public class UserDao{
...
}
它和以下Xml配置等效
<bean id="userDao" class="com.yf.UserDao"/>
除了@Component外,Spring還提供了3個功能基本和@Component等效的註解,分別用於對DAO,Service及Web層的Controller進行註解。
@Repository:用於對DAO實現類進行標註。
@Service:用於對Service實現類進行標註。
@Controller:用於對Controller實現類進行標註。
之所以要在@Component之外提供這3個特殊註解,是爲了讓標註類本身的用途清晰化,完全可以用@Component替代這3個特殊註解,但是,推薦使用特定的註解標註特定的Bean,這樣一眼可以看出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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
<context:component-scan base-package="com.yf"></context:component-scan>
</beans>
通過context命名空間的component-scan的bask-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包裏的所有類,並從類的註解信息中獲取Bean的定義信息。
UserDao類:
@Component("userDao")
public class UserDao {
public void addUser(String user) {
System.out.println("添加User");
}
}
main:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserDao dao = (UserDao) context.getBean("userDao");
dao.addUser("333");
}
}
結果:
添加User
3.自動裝配Bean
3.1使用@Autowired進行自動注入
UserService類:
@Service("userService")
public class UserService {
@Autowired
private UserDao userDao;
public void addUser(String user) {
userDao.addUser(user);
}
}
UserDao類
@Repository("userDao")
public class UserDao {
public void addUser(String user) {
System.out.println("添加User" + user);
}
}
beans.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
<context:component-scan base-package="com.yf"></context:component-scan>
</beans>
main:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserService service = (UserService) context.getBean("userService");
service.addUser("333");
}
}
結果:
添加User333
3.2使用@Autowired的required屬性
@Autowired
private UserDao userDao;
如果容器中沒有一個標註變量類型匹配Bean,那麼容器將會報NoSuchBeanDefinitionException異常,如果希望Spring即使找不到匹配的Bean完成注入也不要拋出異常,可以使用@Autowired(required=false)
@Autowired(required=false)
private UserDao userDao;
...
3.3@Autowired對類方法進行標註
@Service("userService")
public class UserService {
private UserDao userDao;
// 自動將UserDao傳給方法入參
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(String user) {
userDao.addUser(user);
}
}
如果一個方法擁有多個入參,默認情況下,Spring將自動選擇匹配入參類型的Bean進行注入。
3.4@Autowired對集合進行標註
對list進行註解
@Component("myComponent")
public class MyComponent {
@Autowired
private List<BeanInterface> list;
public void say() {
for (BeanInterface bean : list) {
bean.say();
}
}
}
BeanInterface 類:
public interface BeanInterface {
public void say();
}
BeanOneImpl 類:
@Component
public class BeanOneImpl implements BeanInterface {
@Override
public void say() {
System.out.println("BeanOneImpl");
}
}
BeanTowImpl 類:
@Component
public class BeanTowImpl implements BeanInterface {
@Override
public void say() {
System.out.println("BeanTowImpl");
}
}
main:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
MyComponent component = (MyComponent) context.getBean("myComponent");
component.say();
}
}
結果:
BeanOneImpl
BeanTowImpl
4.基於Java類的配置
//將一個POJO標註爲定義Bean的配置類
@Configuration
public class AppConf {
//定義Bean
@Bean
public UserDao userDao() {
return new UserDao();
}
}
@Configuration註解類本身標註了@Component註解,所以任何標註了@Configuration的類,本身也相當於標註了@Component,即它可以像普通Bean一樣被注入其他Bean中。