spring-day01-概述-IOC

一、spring概述

  1. spring 的 開源的輕量級框架
  2. spring的兩大核心:IOC ,AOP

二、spring的EJB的區別(瞭解)

  1. EJB可以說像是一個Web Service,但也不完全是,比如EJB將編寫好的業務組件放置在EJB容器上,然後提供接口給客戶端訪問;但是功能不僅限如此,EJB標準中提供了很多規範等,而這些規範只有在EJB容器才能正常運行。
    EJB是重量級框架
  2. Spring容器取代了原有的EJB容器,因此以Spring框架爲核心的應用無須EJB容器支持,可以在Web容器中運行。
    Spring容器管理的不再是複雜的EJB組件,而是POJO(Plain Old Java Object) Bean。
    Spring輕量級框架

三、耦合和解耦

1. 什麼是耦合
	模塊之間的關聯程度, 依賴程度
2. 什麼是解耦
	降低模塊之間的耦合度(依賴關係)
3. 解耦的目的
	編譯器不依賴(編譯沒有語法錯誤),運行期才依賴(運行可能報錯)
4. 解耦思路
	1) 把全限類名都放到配置文件中
	2)  通過工廠幫助創建對象

四、 解耦代碼–自定義IOC(瞭解)

spring內所有的類都叫bean對象
自己寫beans.xml,自己寫bean工廠讀取xml,靜態存儲在map中 不需要new對象直接獲取,在Test測試類中寫測試,每次獲取方法都一樣
在這裏插入圖片描述

UserDaoImpl和UserServiceImpl內容均爲空
pom.xml 依賴

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>
<dependency>
    <groupId>jaxen</groupId>
    <artifactId>jaxen</artifactId>
    <version>1.1.6</version>
</dependency>

beans.xml

<beans>
    <!--
        用bean標籤配置所有的bean對象
        id:對象的唯一標誌
        class: 全限定類名
    -->
    <bean id="userDao" class="cn.ahpu.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="cn.ahpu.service.impl.UserServiceImpl"></bean>

</beans>

BeanFactory.java 自己實現工廠

package cn.ahpu.factory;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import sun.plugin.javascript.navig.JSType;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 寒面銀槍
 * @create 2020-01-11 15:08
 *
 * 創建bean對象的工廠類
 */
public class BeanFactory {
    private static Map<String,Object> map=new HashMap<String,Object>();

    //提前把所有對象創建出來、存儲
    //用map存儲,方便查找--map相當於一個容器--包含了所有對象
    //靜態代碼塊
    static{
        //獲取xml文件的輸入流對象
        InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");

        //解析xml,獲取xml中所有信息
        SAXReader reader = new SAXReader();
        try {
            //創建文檔對象
            Document doc = reader.read(inputStream);
            //獲取根節點  beans
            Element root = doc.getRootElement();
            //獲取根節點中的所有子節點
                //element("bean");獲取第一個id爲bean的子節點
                //elements("bean")獲取所有id爲bean的子節點
                //element()獲取所有的子節點
            List<Element> beanList = root.elements("bean");
            for (Element element : beanList) {
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");

                //通過className(全限定名)創建對象
                //獲取字節碼
                Class clazz = Class.forName(className);
                //通過反射創建對象
                Object obj = clazz.newInstance();
                //存儲在map中
                    //key:id
                    //value:obj
                map.put(id,obj);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //需要實現的功能:傳入一個名字,獲取一個bean對象
    public static Object getBean(String id){
        //多例直接在此處new一個再返回即可
        return map.get(id);
    }
}

TestCustomIOC.java

package cn.ahpu;

import cn.ahpu.factory.BeanFactory;

/**
 * @author 寒面銀槍
 * @create 2020-01-12 9:24
 */
public class TestCustomIOC {

    public static void main(String[] args){
        Object userService = BeanFactory.getBean("userService");
        System.out.println(userService);
        //兩次獲取一模一樣
        Object userService1 = BeanFactory.getBean("userService");
        System.out.println(userService1);
        //只創建一次 每次拿的都是哪一個 在map中唯一
    }
}

IOC就是幫助我們創建對象的,對象創建好放在容器中,用時直接拿即可

五、spring的IOC入門(掌握)

在這裏插入圖片描述

1.引入依賴 pom.xml

<dependencies>
    <!--引入spring的最核心的依賴
        RELEASE:發行版
        context:同時引入了4個必要核心包: aop,beans,core,expression
    -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
</dependencies>

2.寫核心 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.xsd">

    <!--
        xmlns名稱空間
            http://www.springframework.org/schema/beans 引入bean的名稱空間 引入了裏面就可以使用<bean>了
        xsi: 約束 限制xml的書寫
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            兩句引入約束
            約束有兩種:
                dtd:mybatis
                schema:spring

    -->
    <bean id="userDao" class="cn.ahpu.dao.impl.UserDaoImpl"></bean>

</beans>

工廠肯定不用自己寫了
3. 創建容器對象 根據id獲取對象實例

測試類 TestSpringIOC 直接創建spring的工廠 傳遞beans.xml給它

package cn.ahpu;

import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 寒面銀槍
 * @create 2020-01-12 11:28
 */
public class TestSpringIOC {
    public static void main(String[] args) {
        //創建spring IOC容器
        //直接用spring的工廠就行了  把配置文件名傳給他
        //ClassPathXmlApplicationContext 默認在類路徑(根目錄)下讀取
        ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
        //獲取對象
        Object userDao = ac.getBean("userDao");
        System.out.println(userDao);
    }
}

在這裏插入圖片描述

六、IOC細節

1、容器對象的類結構圖

在這裏插入圖片描述

a、beanFactory 是spring容器的頂層接口
b、常用接口ApplicationContext是 beanFactory子接口
	其實現類有:   ClassPathXmlApplicationContext  -- 從類路徑之下讀取配置文件 (常用)
				 FileSystemXmlApplicationContext - 從絕對路徑指定的配置文件讀取
				 AnnotationConfigApplicationContext -- 純註解配置使用的類 (常用)
c、BeanFactory與ApplicationContext區別(見下面代碼)
	BeanFactory:創建容器對象時,只是加載了配置文件,沒有創建對象
				獲取對象時:才創建對象
	ApplicationContext:在創建容器時只創建單例模式的對象(提前創建了,增加了服務器啓動時間,但縮短程序運行時的時間)
					   多例模式的對象,在獲取時創建

c、BeanFactory與ApplicationContext區別

//applicationContext與BeanFactory的對比
    @Test
    public void testApplicationAndBeanFactory(){
        Resource resource=new ClassPathResource("beans.xml");
        BeanFactory beanFactory=new XmlBeanFactory(resource);
        Object userDao = beanFactory.getBean("userDao");
        System.out.println(userDao);
    }

若xml有錯,beanFactory只有執行到getBean纔會報錯
而 applicationContext在創建ApplicationContext ac時就報錯,說明:了上述區別

2、getBean方法(掌握)

getBean三種獲取方式

<bean id="userDao" class="cn.ahpu.dao.impl.UserDaoImpl" ></bean>
@Test
public void testGetBean(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    //方法1:通過id獲取對象
    //Object userDao = ac.getBean("userDao");

    //方法2:通過類型獲取對象 xml中此類型唯一時方可用 該接口類型有兩個實現類 就不行了
    //UserDao userDao = ac.getBean(UserDao.class);

    //方法3:同時指定id和類型  好處:返回值不再默認Object而是UserDao
    UserDao userDao = ac.getBean("userDao", UserDao.class);

    System.out.println(userDao);
}

name、scope

name:和id一樣
scope:單例 多例

<bean class="cn.ahpu.dao.impl.UserDaoImpl" name="userDao"></bean>
    @Test
    public void testNameScope(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = ac.gtBean("userDao", UserDao.class);
        System.out.println(userDao);
        UserDao userDao2 = ac.getBean("userDao", UserDao.class);
        System.out.println(userDao2);
    }

在這裏插入圖片描述)
說明name和id有相同作用 且默認單例


修改多例配置

<bean class="cn.ahpu.dao.impl.UserDaoImpl" name="userDao" scope="prototype"></bean>
@Test
public void testNameScope(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDao userDao = ac.getBean("userDao", UserDao.class);
    System.out.println(userDao);
    UserDao userDao2 = ac.getBean("userDao", UserDao.class);
    System.out.println(userDao2);
}

在這裏插入圖片描述

springIOC容器默認的單例模式:  單例模式的對象在創建容器時創建,銷燬容器時銷燬
scope:prototype 原型模式(多例模式):獲取時創建,當對象長時間不再被引用, 則被垃圾回收機制回收
scope:singleton :單例模式
scope :request:  請求範圍
scope: session : 回話範圍
scope:global session :全局範圍 -- spring 5的新特性中被刪除了

3、bean對象的範圍和生命週期(掌握)

單例模式的對象在創建容器時創建,銷燬容器時銷燬


UserDaoImpl.java

public class UserDaoImpl implements UserDao {

    public void init(){
        System.out.println("userdao創建了");
    }

    public void destory(){
        System.out.println("userdao銷燬了");
    }
}
<bean class="cn.ahpu.dao.impl.UserDaoImpl" name="userDao" scope="singleton"
            init-method="init" destroy-method="destory"></bean>

測試:

	@Test
    public void testDestoryInit(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//        UserDao userDao = ac.getBean("userDao", UserDao.class);
//        System.out.println(userDao);
        ac.close();
    }

在這裏插入圖片描述

多例對象:獲取時創建,當對象長時間不在被引用, 則被垃圾回收機制回收(回收無法演示)

<bean class="cn.ahpu.dao.impl.UserDaoImpl" name="userDao" scope="prototype"
            init-method="init" destroy-method="destory"></bean>
//多例
@Test
public void testDestoryInit2(){
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("---------------------------------------------");
    UserDao userDao = ac.getBean("userDao", UserDao.class);
    UserDao userDao1 = ac.getBean("userDao", UserDao.class);
    ac.close();
}

在這裏插入圖片描述
getBean獲取時才被創建,ac.close也不會銷燬,長時間不用由垃圾回收自動回收

4、實例化bean的三種方法

1. getBean

最常用的方法
<bean id="name" class="全限類名">
	getBean(name)

2.根據靜態工廠獲取對象(坑)

在這裏插入圖片描述
StaticFactory.java //自己寫個工廠

public class StaticFactory {

    /**
     * 通過靜態工廠獲取對象
     * @return
     */
    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

applicationContext.xml

	 <!--通過靜態工廠獲取UserDao對象
	        class:靜態工廠類(DIY)
	        factory-method: DIY工廠內獲取bean的方法
    -->
    <bean id="userDao" class="cn.ahpu.factory.StaticFactory" factory-method="getUserDao"></bean>

TestSpringIOC.java

//靜態工廠獲取bean
    @Test
    public void testCreateBean(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        Object userDao = ac.getBean("userDao");
        System.out.println(userDao);
    }

3. 根據實例(非靜態)工廠獲取對象(坑)

InstanceFactory.java //自定義實例工廠

//實例工廠創建對象
public class InstanceFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

applicationContext.xml

<!--創建實例工廠對象-->
    <bean id="instanceFactory" class="cn.ahpu.factory.InstanceFactory"></bean>
    <!--通過實例工廠創建UserDao對象-->
    <bean id="userDao2" factory-bean="instanceFactory" factory-method="getUserDao"></bean>

TestSpringIOC.java

    //實例工廠獲取UserDao
    @Test
    public void testCreateBean2(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        Object userDao2 = ac.getBean("userDao2");
        System.out.println(userDao2);
    }

一句話總結上面2、3兩種方法:挖個坑然後自己跳進去 再來一句話:吃飽了撐了找點麻煩消遣下

5、依賴注入

IOC內包含了DI, DI是IOC一個重要體現

a.什麼是依賴注入
	eg:業務層需要持久層的對象,在配置文件中給業務層傳入持久層的對象,就是依賴注入
b. ioc
	控制反轉包含了依賴注入和依賴查找

6、構造方法注入(掌握 constructor-arg)

User.java

public class User {
    private Integer id;
    private String username;
    private Character sex;
    private Date birthday;

    public User(Integer id,String username) {
        this.id = id;
        this.username=username;
    }

    public User() {}

    //省略get/set
}

applicationContext.xml

<!--依賴注入 注意默認調用無參構造方法-->
    <!--先試試構造方法方法傳入屬性值-->
    <bean id="user" class="cn.ahpu.domain.User">
        <!--寫法1: 序號 弊端:有兩個2參構造方法到底調用哪個呢?-->
        <!--<constructor-arg index="0" value="1"></constructor-arg>
        <constructor-arg index="1" value="張三"></constructor-arg>-->

        <!--寫法2::通過構造方法參數類型賦值-->
        <!--<constructor-arg type="java.lang.Integer" value="2"></constructor-arg>
        <constructor-arg type="java.lang.String" value="李四"></constructor-arg>-->

        <!--寫法3:通過構造方法參數名  簡單直觀 且有代碼提示-->
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="username" value="王五"></constructor-arg>
    </bean>

TestSpringIOC.java

 /*測試DI*/
    @Test
    public void TestDI(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) ac.getBean("user");
        System.out.println(user);
        System.out.println(user.getId());
        System.out.println(user.getUsername());
    }

注意:
value 屬性只能賦值簡單的類型:基本數據類型和String類型
ref: pojo類型,複雜類型, 關聯創建好的對象

User.java

public class User {
    private Integer id;
    private String username;
    private Character sex;
    private Date birthday;

    public User(Integer id,String username,Date birthday) {
        this.id = id;
        this.username=username;
        this.birthday=birthday;
    }

    public User() {}

applicationContext.xml

    <bean id="user" class="cn.ahpu.domain.User">
        <!--複雜類型用ref關聯引用-->
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="username" value="王五"></constructor-arg>
        <constructor-arg name="birthday" ref="birthday"></constructor-arg>
    </bean>

    <!--pojo類型自己new一個 不注入構造參數默認當前日期-->
    <bean id="birthday" class="java.util.Date">
        <constructor-arg name="year" value="2020"></constructor-arg>
        <constructor-arg name="month" value="01"></constructor-arg>
        <constructor-arg name="date" value="10"></constructor-arg>
    </bean>

TestDI.java

/*測試DI*/
    @Test
    public void TestDI(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) ac.getBean("user");
        System.out.println(user);
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getBirthday().getYear()+"年"+user.getBirthday().getMonth()+"月");
    }

在這裏插入圖片描述

7、set方法注入(★ 掌握 property)

applicationContext.xml

<!--通過set方法注入-->
    <bean id="user2" class="cn.ahpu.domain.User">
        <!--property:找的是set方法 也就是javabean規範的屬性-->
        <property name="id" value="1"></property>
        <property name="username" value="張三"></property>
        <property name="birthday" ref="birthday"></property>
        <property name="sex" value=""></property>
    </bean>

TestDI

/*測試DI*/
    @Test
    public void TestDI2(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) ac.getBean("user2");
        System.out.println(user);
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getSex());
        System.out.println(user.getBirthday());
    }

在這裏插入圖片描述

8、p名稱空間注入:基於set方法注入(瞭解)

applicationContext.xml頭部引入一個p名稱空間
在這裏插入圖片描述

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

applicationContext.xml 看起來也很簡單 但是無法用於集合屬性

<!--p名稱空間注入-->
    <bean id="user3" class="cn.ahpu.domain.User"
        p:id="2" p:username="李四" p:sex="女" p:birthday-ref="birthday"
    >
    </bean>

TestSpringIOC

/*測試DI3 p名稱空間*/
    @Test
    public void TestDI3(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) ac.getBean("user3");
        System.out.println(user);
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getSex());
        System.out.println(user.getBirthday());
    }

在這裏插入圖片描述

9、注入集合屬性(掌握)

簡單集合

list set array 結構一樣 可以混用

Student.java

public class Student {
    private List<String> list;
    private Set<String> set;
    private String[] strs;
    //省略get/set
}

applicationContext.xml

<!--注入集合屬性-->
    <bean id="student" class="cn.ahpu.domain.Student">
        <!--包裹value的:<list> <set> <array>  可以混用 結構一樣用啥沒差(不影響dom4j的獲取結果) 也即三個標籤可視爲1個-->
        <property name="list">
            <list>
                <value>javaEE</value>
                <value>javaSE</value>
                <value>javaME</value>
            </list>
        </property>

        <property name="set">
            <set>
                <value>javaEE</value>
                <value>javaSE</value>
                <value>javaME</value>
            </set>
        </property>

        <property name="strs">
            <array>
                <value>javaEE</value>
                <value>javaSE</value>
                <value>javaME</value>
            </array>
        </property>

    </bean>

TestSpringIOC

 /*測試DI4 注入集合*/
    @Test
    public void TestDI4(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) ac.getBean("student");
        System.out.println(student.getList());
        System.out.println(student.getSet());
        System.out.println(Arrays.toString(student.getStrs()));
    }

在這裏插入圖片描述

鍵值對

map和props標籤結構一樣也可以混用
Student.java

public class Student {
    private Map<String,String> map;
    private Properties properties;//也是鍵值對 對應properties屬性文件
}

applicationContext.xml

 <!--注入鍵值對集合屬性-->
    <bean id="student" class="cn.ahpu.domain.Student">
        <!--map和props標籤也可以混用-->
        <property name="map">
            <map>
                <entry key="" value="one"></entry>
                <entry key="" value="two"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="">three</prop>
                <prop key="">four</prop>
            </props>
        </property>

    </bean>

TestSpringIOC

/*測試DI4 注入集合*/
    @Test
    public void TestDI4(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) ac.getBean("student");       
        System.out.println(student.getMap());
        System.out.println(student.getProperties());
    }

在這裏插入圖片描述

七、小結

spring第一天
	
 spring介紹
	spring 輕量級框架
	兩個核心:IOC 控制反轉 包括依賴注入和依賴查找  , 主要作用:降低耦合度
		AOP:面向切面編程
 耦合和解耦
 springIOC的入門
	1)引入依賴   配置一個spring-context 就包含這麼多
		spring-context-5.0.2.RELEASE.jar
		spring-core-5.0.2.RELEASE.jar
		spring-aop-5.0.2.RELEASE.jar
		spring-beans-5.0.2.RELEASE.jar
		spring-expression-5.0.2.RELEASE.jar
	2) 配置文件:beans.xml    applicationContext.xml
		創建對象 <bean/>
	3) 測試
		創建容器對象
		從容器中獲取對象:getBean("id | name")  getBean(Class) , getBean("id | name", Class )
  容器對象的類結構圖
	BeanFactory: 
	ApplicationContext:在創建容器時創建單例模式的對象
			多例模式的對象在使用時創建對象
 Bean 	
	scope: 
	
  依賴注入
	構造方法 : 按照,索引,名稱,類型注入
	set方法注入:  必須提供set方法
		<property name="username" >
	p名稱空間注入
		1) 添加p名稱空間
		2) p:username=""

  賦值
	value: 賦值簡單類型
	ref:賦值pojo類型
  注入集合屬性: list ,set ,array
	       map properties
發佈了388 篇原創文章 · 獲贊 89 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章