Spring學習之Spring 配置(四)

要使應用程序中的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中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章