springIOC彙總

Spring

Spring的兩大核心機制(IOC、IOP)

  • IOC(控制反轉)/DI(依賴注入)
  • AOP(面向切面編程)

IOC

  • 創建一個maven工程
  • 創建一個Student類
package cn.guoke1.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int age;

}

以前我們需要這個類時,我們需要new這個類

        Student student = new Student();
        student.setAge(10);
        student.setId(20);
        student.setName("張三");
        System.out.println(student);

在使用Spring後我們將這個類交給Spring來管理,在使用時直接拿來用就可以了

  • 導入Spring依賴(只需要導入spring-context)就可以了
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
  • 創建一個spring.xml 用來配置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-3.0.xsd">

    <bean id="student" class="cn.guoke1.pojo.Student">
        <property name="name" value="張三"></property>
        <property name="age" value="12"></property>
        <property name="id" value="20"></property>
    </bean>

</beans>
  • 測試
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Student student =(Student) context.getBean("student");
        System.out.println(student);

配置文件

  • 通過bean標籤來完成對象的管理

    • di:對象名
    • class:對象的模板類(所有交給IOC容器管理的類必須又無參構造,因爲Spring底層是通過反射機制來創建對象,調用的是無參構造)
  • 對象的成員變量是通過property標籤來完成賦值。

    • name:成員變量名
    • value:成員變量值(j基本數據類型、String類型直接賦值,如果是引用類型,不能通過value賦值)
    • ref:將IOC中的另一個bean賦值給當前成員變量(DI)
        <bean id="student" class="cn.guoke1.pojo.Student">
            <property name="name" value="張三"></property>
            <property name="age" value="12"></property>
            <property name="id" value="20"></property>
            <property name="teacher" ref="teacher"></property>
        </bean>
    
        <bean id="teacher" class="cn.guoke1.pojo.Teacher">
            <property name="name" value="張老師"></property>
            <property name="age" value="20"></property>
        </bean>
        
    

使用有參函數來創建對象

    <bean id="student" class="cn.guoke1.pojo.Student">
        <constructor-arg name="name" value="張三"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
        <constructor-arg name="id" value="10"></constructor-arg>
        <constructor-arg name="teacher" ref="teacher"></constructor-arg>
    </bean>

    <bean id="teacher" class="cn.guoke1.pojo.Teacher">
        <property name="name" value="張老師"></property>
        <property name="age" value="20"></property>
    </bean>

在測試時可以使用

        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Student student = context.getBean(Student.class);
        System.out.println(student);

來獲取實例 ,但這種方法只能在xml只能有以惡一個實例

實現原理

  • 讀取配置文件,解析 XML。
  • 通過反射機制實例化配置文件中所配置所有的 bean。
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ClassPathXmlApplicationContext implements ApplicationContext {
    private Map<String,Object> ioc = new HashMap<String, Object>();
    public ClassPathXmlApplicationContext(String path){
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read("./src/main/resources/"+path);
            Element root = document.getRootElement();
            Iterator<Element> iterator = root.elementIterator();
            while(iterator.hasNext()){
                Element element = iterator.next();
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");
                //通過反射機制創建對象
                Class clazz = Class.forName(className);
                //獲取無參構造函數,創建目標對象
                Constructor constructor = clazz.getConstructor();
                Object object = constructor.newInstance();
                //給目標對象賦值
                Iterator<Element> beanIter = element.elementIterator();
                while(beanIter.hasNext()){
                    Element property = beanIter.next();
                    String name = property.attributeValue("name");
                    String valueStr = property.attributeValue("value");
                    String ref = property.attributeValue("ref");
                    if(ref == null){
                        String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
                        Field field = clazz.getDeclaredField(name);
                        Method method = clazz.getDeclaredMethod(methodName,field.getType());
                        //根據成員變量的數據類型將 value 進行轉換
                        Object value = null;
                        if(field.getType().getName() == "long"){
                            value = Long.parseLong(valueStr);
                        }
                        if(field.getType().getName() == "java.lang.String"){
                            value = valueStr;
                        }
                        if(field.getType().getName() == "int"){
                            value = Integer.parseInt(valueStr);
                        }
                        method.invoke(object,value);
                    }
                    ioc.put(id,object);
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e){
            e.printStackTrace();
        } catch (NoSuchMethodException e){
            e.printStackTrace();
        } catch (InstantiationException e){
            e.printStackTrace();
        } catch (IllegalAccessException e){
            e.printStackTrace();
        } catch (InvocationTargetException e){
            e.printStackTrace();
        } catch (NoSuchFieldException e){
            e.printStackTrace();
        }
    }

    public Object getBean(String id) {
        return ioc.get(id);
    }
}

給 bean 注入集合

    <bean id="student" class="cn.guoke1.pojo.Student">
    <property name="id" value="2"></property>
    <property name="name" value="李四"></property>
    <property name="age" value="33"></property>
    <property name="addresses">
        <list>
            <ref bean="address"></ref>
            <ref bean="address2"></ref>
        </list>
    </property>
</bean>

scope 作用域

Spring 管理的 bean 是根據 scope 來生成的,表示 bean 的作用域,共4種,默認值是 singleton。

  • singleton:單例,表示通過 IoC 容器獲取的 bean 是唯一的。
  • prototype:原型,表示通過 IoC 容器獲取的 bean 是不同的。
  • request:請求,表示在一次 HTTP 請求內有效。
  • session:回話,表示在一個用戶會話內有效。

request 和 session 只適用於 Web 項目,大多數情況下,使用單例和原型較多。

prototype 模式當業務代碼獲取 IoC 容器中的 bean 時,Spring 纔去調用無參構造創建對應的 bean。

singleton 模式無論業務代碼是否獲取 IoC 容器中的 bean,Spring 在加載 spring.xml 時就會創建 bean。

Spring 的繼承

與 Java 的繼承不同,Java 是類層面的繼承,子類可以繼承父類的內部結構信息;Spring 是對象層面的繼承,子對象可以繼承父對象的屬性值。

配置:parent="student2" 

<bean id="student" class="cn.guoke1.pojo.Student">
    <property name="id" value="1"></property>
    <property name="name" value="張三"></property>
    <property name="age" value="22"></property>
    <property name="addresses">
        <list>
            <ref bean="address"></ref>
            <ref bean="address2"></ref>
        </list>
    </property>
</bean>

<bean id="address" class="cn.guoke1.pojo.Student">
    <property name="id" value="1"></property>
    <property name="name" value="科技路"></property>
</bean>

<bean id="address2" class="cn.guoke1.pojo.Student">
    <property name="id" value="2"></property>
    <property name="name" value="高新區"></property>
</bean>

<bean id="stu" class="com.southwind.entity.Student" parent="student2">
    <property name="name" value="李四"></property>
</bean>

Spring 的繼承關注點在於具體的對象,而不在於類,即不同的兩個類的實例化對象可以完成繼承,前提是子對象必須包含父對象的所有屬性,同時可以在此基礎上添加其他的屬性。

Spring依賴

與繼承類似,依賴也是描述 bean 和 bean 之間的一種關係,配置依賴之後,被依賴的 bean 一定先創建,再創建依賴的 bean,A 依賴於 B,先創建 B,再創建 A。

Spring 的 p 命名空間

p 命名空間是對 IoC / DI 的簡化操作,使用 p 命名空間可以更加方便的完成 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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <bean id="student" class="cn.guoke1.pojo.Student" p:id="1" p:name="張三" p:age="22" p:address-ref="address"></bean>

    <bean id="address" class="cn.guoke1.pojo.Student" p:id="2" p:name="李四"></bean>

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