Spring容器的xml配置及註解使用

Spring介紹

框架:高度抽取可重用代碼的一種設計;高度的通用性;

​ 多個可重用模塊的集合,形成某個領域的整體解決方案

Spring框架:容器:可以管理所有的組件;IOC和AOP

IOC(容器):Iversion Of Control 控制反轉

用容器來整合框架

控制:資源的獲取

  • 主動式(自己用什麼資源就創建new)
  • 被動式(資源的獲取交給容器創建和設置)

容器:從主動的new資源爲被動的接受資源

DI(Dependency Injection):依賴注入(是IOC思想的具體實現)。容器能知道那個組件運行的時候,需要另一個組件,容器通過反射的形式,將容器中的準備好的對象注入(利用反射給屬性賦值)到最初的那個組件中。

容器中對象的創建在容器創建的時候就創建了。

一個bean對應一個對象

同一個組件在ioc中是單例的。

javabean的屬性名是由getter/setter方法決定的,去掉set之後將首字母小寫之後得到的字符串就是屬性名。

配置文件:

bean的創建原理

bean的創建就是框架利用反射new出來的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 id="stu1" class="com.onezero.Student">
        <property name="name" value="張三"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="stu2" class="com.onezero.Student">
        <property name="name" value="李四"></property>
        <property name="age" value="19"></property>
    </bean>
    <bean id="stu3" class="com.onezero.Student">
        <constructor-arg name="age" value="20"></constructor-arg>
        <constructor-arg name="name" value="onezero"></constructor-arg>
    </bean>
    <bean id="stu4" class="com.onezero.Student">
        <constructor-arg value="馬雲"></constructor-arg>
        <constructor-arg value="40"></constructor-arg>
    </bean>
</beans>

在配置文件中使用property標籤是通過set方法來賦值的。通過constructor-arg可以調用有參構造器賦值。若是嚴格按照有參構造器中參數出現的順序寫屬性,則可以省略name。

若沒有嚴格按照構造器中給出的參數數據賦值,可以通過index指定賦給第幾個參數。

若是構造器進行了重載且參數個數一樣,如果想省略name需要指定type(即參數類型)

綜上所述,不省略name是一種比較常見的配置方法。

通過p命名空間爲bean賦值

通過get/set方法進行賦值

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stu05" class="com.onezero.Student" p:age="19" p:name="小紅"></bean>

</beans>
獲取bean對象的三種方法:
//通過bean的id獲取bean的實例
public void dmeo() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
        System.out.println("ioc配置完成");
        Student stu1 = (Student) ac.getBean("stu1");
        System.out.println(stu1);
    }

//通過bean的類型從IOC容器中獲取bean的實例,優點是可以不用進行類型轉換,缺點是若配置文件中存在多個該類型的bean,就會報錯
public void demo2(){
        Student stu = ac.getBean(Student.class);
        System.out.println(stu);
    }

//改進
Student stu = ac.getBean("stu1",Student.class);
通過配置文件進行復雜的賦值:
package com.onezero;


import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Student {
    private String name;
    private Integer age;
    private Car car;
    private List<Book> list;
    private Map<String,Object> map;
    private Set<Integer> set;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", properties=" + properties +
                '}';
    }

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    public Set<Integer> getSet() {
        return set;
    }

    public void setSet(Set<Integer> set) {
        this.set = set;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    private Properties properties;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public List<Book> getList() {
        return list;
    }

    public void setList(List<Book> list) {
        this.list = list;
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
        System.out.println("有參");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Student() {
        System.out.println("對象被創建了");
    }
}

<?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:p="http://www.springframework.org/schema/p"
       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 https://www.springframework.org/schema/util/spring-util.xsd">
    <bean id="stu" class="com.onezero.Student">
        <property name="age" value="19"></property>

        <property name="name">
            <null></null>
        </property>
        <!--ref:引用外部bean,是嚴格的引用-->
        <property name="car" ref="car"></property>

        <property name="list">
            <!--爲list賦值-->
            <list>
                <!--內部bean無法被外部獲取到-->
                <bean class="com.onezero.Book" p:name="西遊記" p:author="吳承恩" p:price="20"></bean>
                <!--使用外部引用-->
                <ref bean="book1"></ref>
            </list>
        </property>

        <property name="map">
            <map>
                <entry key="book" value-ref="book1"></entry>
                <entry key="name" value="小紅"></entry>
                <entry key="num">
                    <value>126</value>
                </entry>
            </map>
        </property>

        <property name="set">
            <set>
                <value>15</value>
                <value>15</value>
                <value>155</value>
            </set>
        </property>

        <property name="properties">
            <props>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>

    </bean>

    <bean id="car" class="com.onezero.Car">
        <property name="branch" value="寶馬"></property>
        <property name="price" value="300000"></property>
    </bean>

    <bean id="book1" class="com.onezero.Book" p:price="30" p:author="金魚醬" p:name="人間告白">
    </bean>
</beans>
通過util命名空間創建集合類型的bean,方便引用
<!--util:map相當於new了一個LinkedHashMap-->   
<util:map id="map">
        <entry key="book" value-ref="book1"></entry>
        <entry key="name" value="小紅"></entry>
        <entry key="num">
            <value>126</value>
        </entry>
    </util:map>

    <bean id="stu2" class="com.onezero.Student">
        <property name="map" ref="map"></property>
    </bean>
級聯屬性

級聯屬性:屬性的屬性(例如:car.price)

parent屬性

parent:指定當前的bean的配置信息繼承於哪個bean

abstract=“true”

abstract=“true”:表示當前bean的配置是一個抽象的,不能獲取它的實例,只能被繼承

depends-on:bean之間的依賴

bean 裏面的依賴只是指bean的創建順序罷了。若是沒有依賴,創建順序按照在配置文件中的書寫順序。若是有了依賴關係,那麼先創建被依賴的bean(被依賴的bean可以是有多個)

bean的作用域

bean的作用域指bean是否是單實例的。默認情況下,bean是單實例的。

scope=“prototype”:多實例

  • 容器啓動時默認不去創建多實例的bean
  • 獲取的時候這個bean纔會創建
  • 每次獲取都創建一個新的對象

scope=“singleton”:單實例(默認)

  • 在容器啓動完成之前就創建好了對象,保存到容器
  • 獲取到的bean一直是一樣的
靜態工廠和實例工廠

工廠模式:工廠幫我們創建對象。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。

  • 靜態工廠:工廠本身不用創建對象,通過靜態方法調用
    • factory-method:使用靜態工廠中的那個方法
  • 實例工廠:工廠本身需要創建對象
    • factory-bean:指定使用哪個工廠
    • factory-method:使用靜態工廠中的那個方法
<!--靜態工廠方法創建bean-->
<bean id="stu1" class="com.onezero.factory.StaticFactory" factory-method="getStudent">
    <constructor-arg value="李四"></constructor-arg>
</bean>
<!--實例工廠創建bean-->
    <bean id="stuFactory" class="com.onezero.factory.InstanceFactory"></bean>
    <bean id="stu2" class="com.onezero.Student" factory-bean="stuFactory" factory-method="getStudent">
        <constructor-arg value="張三"></constructor-arg>
    </bean>
  • FactoryBean是Spring的一個接口,只要是這個接口的實現類,Spring就認爲這是個工廠類

    步驟:寫一個實現類;在spring中配置

    public class MyFactory implements FactoryBean<Book> {
        @Override
        public Book getObject() throws Exception {
            System.out.println("創建一個實例");
            Book book=new Book();
            return book;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Book.class;
        }
    }
    

    FactoryBean:獲取的時候才創建實例;ioc啓動的時候不會創建實例

bean的生命週期

單實例的bean容器啓動時就創建好,容器關閉就會銷燬創建的bean

多實例bean獲取是纔會創建。

在spring中也可以通過方法來指定生命週期。

單例bean的生命週期:構造器–初始化方法–(容器關閉)銷燬方法

多例bean的生命週期:(獲取bean)構造器–初始化方法 就算是容器關閉也不會調用銷燬方法

<bean id="book" class="com.onezero.Book" init-method="init" destroy-method="destory" scope="prototype"></bean>
 private ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("ioc5.xml");
//ApplicationContext接口中沒有close方法
bean的後置處理器

後置處理器:可以在bean的初始化前後調用方法。

使用步驟:實現 BeanPostProcessor接口;在配置文件中註冊

public class BeanPostProcessorTest implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+":將要調用初始化方法.這個bean是"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }
}

<bean id="beanPostProcessor" class="com.onezero.test.BeanPostProcessorTest"></bean>
引用外部屬性文件

數據庫連接池作爲單實例是最好的,一個項目就一個連接池。

<context:property-placeholder location="classpath:durid.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="username" value="${usernameH}"></property>
    <property name="password" value="${password}"></property>
    <property name="url" value="${url}"></property>
    <property name="driverClassName" value="${driver}"></property>
</bean>

因爲username是Spring中的關鍵字,所以在.properties時不能使用username,可以改爲jdbc.username

自動裝配

autowired(xml)

  • byType
  • byName
  • constructor

通過註解@Autowored實現自動裝配,它可以用於成員變量、構造器及方法,不過只能用於裝配引用。

SpEL:Spring Expression Language
#{}
${}
//調用靜態方法
#{T(全類名).方法}
通過註解將bean加入容器
  • @Component
  • @Repository:持久層
  • @Controller:控制層
  • @Service:業務層
    之後要在xml中加入
<context:component-scan base-package=""/>

Spring 會掃描所有base-package下的類。

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