1. 程式人生 > 實用技巧 >2.spring(二)

2.spring(二)

IOC理論推導 控制反轉

個人理解:當dao層有一個介面,很多實現類的時候,使用者的每一個請求進來,我們都需要手動的去修改程式碼,控制權在程式設計師手上,但當我們使用set方式的時候,請求就隨著使用者的需求變化,控制權就在使用者手上(底層:set原理)

  • 之前,程式是主動的建立物件,控制權在程式手上
  • 使用了set注入之後,程式設計師不在有主動權,而是被動的接收物件
private UserDao userDao = new UserDaoImpl();
private UserDao userDao;
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

將主動的建立物件改為了被動的接收物件

這種思想,從本質上解決了問題,我們不再去管理物件的建立了,系統的耦合性大大降低,可以更加專注的在業務上實現

IOC本質 控制反轉

控制反轉(ioc)是一種設計思想,DI是實現IOC的一種方法,也有人認為DI是IOC的另外一種說法,沒有IOC的程式中,我們使用面向物件程式設計,物件的建立與物件的依賴關係完全硬編碼在程式中,物件的建立由程式自己控制,控制反轉後將物件的建立移交給第三方,個人認為所謂的控制反轉就是獲得物件的以來方式反轉了

                              上圖使用到的就是IOC容器

IOC是spring框架的核心內容,使用多種方法完美的實現了IOC,可以使用xml配置,也可以使用註解配置,新版本的spring可以實現零配置IOC


spring容器在被初始化的時候,先讀取配件(讀取bean),根據配置檔案或元素據建立組織物件存入容器中,程式使用時,再從IOC容器中取出需要的物件

採用xml配置bean的時候,bean的定義資訊和實現是分離的,而採用註解的方式,可以把兩者合為一體,bean的定義資訊直接以註解的形式定義在實現類中,從而達到零配置的目的

控制反轉是一種通過描述(xml或註解)並通過第三方去生產或獲取特定的物件方式,在spring中實現控制反轉的是IOC容器,其實現方式就是依賴注入DI

helloSpring

/**
實體類
*/
public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}
/**
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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--使用spring建立物件,在spring中,這些都成為bean
    Hellow hellow = new Hellow()
    型別    變數名 =  new 型別()

    bean = 物件     new hellow
    id     變數名
    class  new 的物件
    property  相當於給物件的屬性設定一個值
    -->

<!--    bean可以放多個,bean就是一個容器-->
    <bean id="hellow" class="com.cdl.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>
/**
myTest
*/
public class MyTest {
    public static void main(String[] args) {
        //獲取spring的上下文物件
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //我們的物件現在都在spring中管理了,我們要使用直接去取出來即可
        Hello hellow = (Hello) context.getBean("hellow");
        System.out.println(hellow.toString());
    }
}

Hellow物件是誰建立的?
---- spring建立的

Hellow物件的屬性怎麼設定的?
spring容器設定的

這個過程就叫控制反轉

  • 控制:誰來控制物件的建立,傳統應用的物件是有程式本身建立的,使用spring後,物件的建立由spring建立
  • 反轉:程式本身不建立物件,而是被動的接收
  • 依賴注入:利用set方法注入
  • IOC就是一種思想,由主動程式設計程式設計了被動接收

IOC建立物件的方式

  • 使用無參構造器(預設)
<bean id="stu2" class="com.bjsxt.spring2.Student"></bean>
  • 使用有參構造器
    • 下標賦值
    • 型別
    • 引數名

```<bean id="stu3" class="com.bjsxt.spring2.Student">
        <!--<constructor-arg name="a" value="18"></constructor-arg>
        <constructor-arg name="name" value="zs"></constructor-arg>
        <constructor-arg name="sex" value="男"></constructor-arg>-->
        <constructor-arg name="a" index="1" type="int" value="123"></constructor-arg>
        <constructor-arg name="b" index="0" type="java.lang.String" value="456"></constructor-arg>
    </bean>

總結:在配置檔案載入的時候,容器中管理的物件,就已經初始化了

spring配置說明

  • alias 別名
<alias name="user" alias="userNew"/>

若添加了別名,也可以通過別名獲取物件

  • import 引入
    一般用於團隊開發使用,可以將多個配置檔案,匯入合併為一個
<import resources="bean.xml"/>
<import resources="beansNew.xml"/>

依賴注入 DI

三種方式

  • 構造器注入(前面寫過了)
  • set方式注入

實體類

/**
address類
*/
@Data
public class Address {
    private String address;
}
/**
student類
*/
@Data
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,Object> card;
    private Set<String> games;
    private String wife;
    private Properties properties;
}

配置檔案

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

    <bean id="address" class="com.cdl.pojo.Address">
        <property name="address" value="重慶"></property>
    </bean>

    <bean id="student" class="com.cdl.pojo.Student">
<!--        第一種,直接注入-->
        <property name="name" value="陳丹龍"></property>
<!--        第二種,bean注入,使用ref
因為是一個類,現在上面使用bean注入address,然後是類,應該使用ref-->
        <property name="address" ref="address"></property>

<!--        第三種,陣列注入-->
        <property name="books">
            <array>
                <value>三國演義</value>
                <value>紅樓夢</value>
                <value>水滸傳</value>
                <value>西遊記</value>
            </array>
        </property>

<!--        list-->
        <property name="hobbys">
            <list>
                <value>聽歌</value>
                <value>看電影</value>
                <value>寫程式碼</value>
            </list>
        </property>

<!--        map-->
        <property name="card">
            <map>
                <entry key="身份證" value="420821199999999999"></entry>
                <entry key="銀行卡" value="669826656366632565"></entry>
            </map>
        </property>

<!--        set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>CF</value>
            </set>
        </property>

<!--        NULL-->
        <property name="wife">
            <null></null>
        </property>

<!--        Properties配置檔案-->
        <property name="properties">
            <props>
                <prop key="username">admin</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>

</beans>
/**
測試類
*/
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }

    /**
     Student(
     name=陳丹龍, address=Address(address=重慶),
     books=[三國演義, 紅樓夢, 水滸傳, 西遊記],
     hobbys=[聽歌, 看電影, 寫程式碼],
     card={身份證=420821199999999999, 銀行卡=669826656366632565},
     games=[LOL, CF],
     wife=null,
     properties={password=123456, username=admin})
     */

}
  • 拓展方式 c名稱空間注入,P名稱空間注入

P名稱空間注入 屬性的注入
c名稱空間注入,構造器的注入

public class User {
    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    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;
    }
}
<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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    p名稱空間,直接賦值屬性的值-->
    <bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍"/>

<!--    c名稱空間,直接賦值屬性的值-->
    <bean id="name" class="com.cdl.pojo.User" c:age="18" c:name="陳丹龍"/>

</beans>
public class MyTest02 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = context.getBean("user",User.class);
        System.out.println(user);

    }
}

總結:P和C名稱空間不能直接使用,需要匯入xml約束

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

Bean的作用域

  • singleton 單例模式---預設級別---同一個物件呼叫多次,也只會建立一個
 <bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍" scope="singleton"/>
  • prototype 原型模式---每次從容器中get的時候,都會產生一個新的物件
 <bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍" scope="prototype"/>
  • request,session,application,websocket這些都是在web開發中用到的

Bean的自動裝配

  • 自動裝配是spring滿足Bean依賴的一種方式
  • spring會在上下文中自動尋找,並自動給Bean裝配屬性(手動裝配:自己手動在配置檔案中給屬性設定預設值)
  • 在spring中,有三種自動裝配的方式
    • 在xml中顯示的配置
    • 在java中顯示配置
    • 隱試的自動裝配Bean【重要】

環境搭建(eg:一個人有兩隻寵物)

public class Cat {
    public void show(){
        System.out.println("miao~~~");
    }
}
public class Dog {
    public void show(){
        System.out.println("wang~~~");
    }
}

@Data
public class People {
    private Cat cat;
    private Dog dog;
    private String name;
}
<?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="cat" class="com.cdl.pojo.Cat"></bean>
    <bean id="dog" class="com.cdl.pojo.Dog"></bean>

    <bean id="people" class="com.cdl.pojo.People">
        <property name="name" value="陳丹龍"></property>
        <property name="cat" ref="cat"></property>
        <property name="dog" ref="dog"></property>
    </bean>
</beans>
public class Tset {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people = context.getBean("people",People.class);
        people.getCat().show();
        people.getDog().show();
    }
}

ByName自動裝配

<?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="cat" class="com.cdl.pojo.Cat"></bean>
    <bean id="dog" class="com.cdl.pojo.Dog"></bean>

    <bean id="people" class="com.cdl.pojo.People" autowire="byName">
        <property name="name" value="陳丹龍"></property>
    </bean>
</beans>

ByName會自動在容器上下文查詢和自己物件set方法後面的值對應的BeanId

ByType自動裝配

<?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="cat12" class="com.cdl.pojo.Cat"></bean>
  <bean id="dog12" class="com.cdl.pojo.Dog"></bean>

  <bean id="people" class="com.cdl.pojo.People" autowire="byType">
      <property name="name" value="陳丹龍"></property>
  </bean>
</beans>

總結:ByName的時候,需要保證所有的bean的ID唯一,並且這個bean需要和自動注入的屬性的set方法的值一致
ByType的時候,需要保證所有的bean的class唯一,並且這個時候的bena需要和自動注入的屬性保持一致