spring-ioc一學就會

韓利鵬發表於2020-10-18

1.IOC介紹

  1. IOC的作用是控制反轉,把物件建立和物件之間的呼叫過程,交給 Spring 進行管理
  2. 使用 IOC 目的:為了耦合度降低
  3. IOC的原理是使用了xml 解析、工廠模式、反射

2.IOC的bean管理

Bean管理是指spring建立物件注入屬性

2.1 基於xml方式的建立物件

2.1.1 基於 xml 方式建立物件

<bean id="user" class="com.spring5.User"></bean>
  1. 在 spring 配置檔案中,使用 bean 標籤,標籤裡面新增對應屬性,就可以實現物件建立
  2. 在 bean 標籤有很多屬性,介紹常用的屬性
            - id 屬性:唯一標識
            - class 屬性:類全路徑(包類路徑)
  3. 建立物件時候,預設也是執行無引數構造方法完成物件建立

2.1.2 基於 xml 方式注入屬性

DI:依賴注入,就是注入屬性

2.1.2.1 第一種注入方式:使用 set 方法進行注入

首先建立類,定義屬性和對應的 set 方法

/** 
 * 演示使用set方法進行注入屬性 
 */ 
public class Book { 
    //建立屬性 
    private String bname; 
    private String bauthor; 
    //建立屬性對應的 set 方法 
    public void setBname(String bname) { 
        this.bname = bname; 
    } 
    public void setBauthor(String bauthor) { 
        this.bauthor = bauthor; 
    } 
}

然後在 spring 配置檔案配置物件建立,配置屬性注入

<!--2 set方法注入屬性--> 
<bean id="book" class="com.spring5.Book"> 
    <!--使用property完成屬性注入 
        name:類裡面屬性名稱 
        value:向屬性注入的值 
    --> 
    <property name="bname" value="易筋經"></property> 
    <property name="bauthor" value="達摩老祖"></property> 
</bean> 

2.1.2.2 使用有引數構造進行注入

/** 
 * 使用有引數構造注入 
 */ 
public class Orders { 
    //屬性 
    private String oname; 
    private String address; 
    //有引數構造 
    public Orders(String oname,String address) { 
        this.oname = oname; 
        this.address = address; 
    } 
}
<!-- 有引數構造注入屬性--> 
<bean id="orders" class="com.spring5.Orders"> 
    <constructor-arg name="oname" value="電腦"></constructor-arg> 
    <constructor-arg name="address" value="China"></constructor-arg> 
</bean> 

2.1.2.3 注入屬性

   外部bean(其實是靠set來賦值的)

<!--1 service和dao 物件建立--> 
<bean id="userService" class="com.spring5.service.UserService"> 
    <!--注入userDao 物件 
        name屬性:類裡面屬性名稱 
        ref屬性:建立userDao物件bean標籤 id值 
    --> 
    <property name="userDao" ref="userDaoImpl"></property> 
</bean> 
<bean id="userDaoImpl" class="com.spring5.dao.UserDaoImpl"></bean> 

           內部bean(其實是靠set來賦值的)

<bean id="emp" class="com.atguigu.spring5.bean.Emp"> 
    <!--設定兩個普通屬性--> 
    <property name="ename" value="lucy"></property> 
    <property name="gender" value=""></property> 
    <!--設定物件型別屬性--> 
    <property name="dept"> 
        <bean id="dept" class="com.atguigu.spring5.bean.Dept"> 
            <property name="dname" value="安保部"></property> 
        </bean> 
    </property> 
</bean> 

2.1.2.4 xml 注入集合屬性

<bean id="stu" class="com.spring5.collectiontype.Stu"> 
    <!--陣列型別屬性注入--> 
    <property name="courses"> 
        <array> 
            <value>java課程</value> 
            <value>資料庫課程</value> 
        </array> 
    </property> 
    <!--list型別屬性注入--> 
    <property name="list"> 
        <list> 
            <value>張三</value> 
            <value>小三</value> 
        </list> 
    </property> 
    <!--map型別屬性注入--> 
    <property name="maps"> 
        <map> 
            <entry key="JAVA" value="java"></entry> 
            <entry key="PHP" value="php"></entry> 
        </map> 
    </property> 
    <!--set型別屬性注入--> 
    <property name="sets"> 
        <set> 
            <value>MySQL</value> 
            <value>Redis</value> 
        </set> 
    </property> 
</bean> 
<!--建立多個course 物件--> 
<bean id="course1" class="com.spring5.collectiontype.Course"> 
    <property name="cname" value="Spring5 框架"></property> 
</bean> 
<bean id="course2" class="com.spring5.collectiontype.Course"> 
    <property name="cname" value="MyBatis 框架"></property> 
</bean> 
<!--注入list集合型別,值是物件--> 
<property name="courseList"> 
    <list> 
        <ref bean="course1"></ref> 
        <ref bean="course2"></ref> 
    </list> 
</property> 

2.1.2.5 工廠bean的形式注入

1、Spring 有兩種型別 bean,一種普通 bean,另外一種工廠 bean(FactoryBean) 
2、普通 bean:在配置檔案中定義 bean 型別就是返回型別 
3、工廠 bean:在配置檔案定義 bean 型別可以和返回型別不一樣 
	第一步 建立類,讓這個類作為工廠 bean,實現介面 FactoryBean 
	第二步 實現介面裡面的方法,在實現的方法中定義返回的 bean 型別 
public class MyBean implements FactoryBean<Course> { 
    //定義返回bean 
    @Override 
    public Course getObject() throws Exception { 
        Course course = new Course(); 
        course.setCname("abc"); 
        return course; 
    } 
    @Override 
    public Class<?> getObjectType() { 
        return null; 
    } 
    @Override 
    public boolean isSingleton() { 
        return false; 
    } 
} 
<bean id="myBean" class="com.spring5.factorybean.MyBean"> 
</bean> 

2.1.2.6 xml 注入其他型別屬性

(1)null 值 
<!--null值--> 
<property name="address"> 
    <null/> 
</property> 

(2)屬性值包含特殊符號 
<!--屬性值包含特殊符號 
    1 把<>進行轉義 &lt; &gt; 
    2 把帶特殊符號內容寫到 CDATA 
--> 
<property name="address"> 
    <value><![CDATA[<<南京>>]]></value> 
</property> 

2.2 基於註解建立物件

2.2.1 開啟註解

<!--示例1 
    use-default-filters="false" 表示現在不使用預設 filter,自己配置 filter 
    context:include-filter ,設定掃描哪些內容 
--> 
<context:component-scan base-package="com.hanlp" use-default-
filters="false"> 
    <context:include-filter type="annotation" 
                            
expression="org.springframework.stereotype.Controller"/> 
</context:component-scan> 
 
<!--示例2 
    下面配置掃描包所有內容 
    context:exclude-filter: 設定哪些內容不進行掃描 
--> 
<context:component-scan base-package="com.hanlp"> 
    <context:exclude-filter type="annotation" 
                            
expression="org.springframework.stereotype.Controller"/> 
</context:component-scan>

2.2.2 例項化物件

1@Component2@Service3@Controller4@Repository 
// 上面四個註解功能是一樣的,都可以用來建立bean 例項 
// 這些註解都是作用在類上,加註在類上後掃描到後會建立預設單例物件

例如:

@Component(value = "userService")  //<bean id="userService" class=".."/> 
public class UserService { 
    public void add() { 
        System.out.println("service add......."); 
    } 
} 

2.2.3 注入物件

  1. @Autowired:根據屬性型別進行自動裝配
// 第一步 把 service 和 dao 物件建立,在 service 和 dao 類新增建立物件註解 
// 第二步 在 service 注入 dao 物件,在 service 類新增 dao 型別屬性,在屬性上面使用註解 
@Service 
public class UserService { 
    //定義dao型別屬性 
    //不需要新增set 方法 
    //新增註入屬性註解 
    @Autowired 
    private UserDao userDao; 
 
    public void add() { 
        System.out.println("service add......."); 
        userDao.add(); 
    } 
} 
  1. @Qualifier:根據名稱進行注入
//這個@Qualifier 註解的使用,和上面@Autowired 一起使用 
//定義dao型別屬性 
//不需要新增set方法 
//新增註入屬性註解 
@Autowired  //根據型別進行注入 
@Qualifier(value = "userDaoImpl1") //根據名稱進行注入 
private UserDao userDao; 
  1. @Resource:可以根據型別注入,可以根據名稱注入
//@Resource  //根據型別進行注入 
@Resource(name = "userDaoImpl1")  //根據名稱進行注入 
private UserDao userDao; 
  1. @Value:注入普通型別屬性
@Value(value = "abc") 
private String name; 

3. 例項是單例項還是多例項

在 Spring 裡面,預設情況下,bean 是單例項物件

  1. scope設定為singleton的時候為單例,預設的時候就是singleton,載入spring配置的時候就會建立單例物件。
  2. scope設定為prototype的時候為多例項,呼叫的時候才會建立,每次呼叫都建立新的例項。
    eg:註解形式
@Service
@Scope("prototype")
public class PersonTemplate {

eg:xml形式

<bean id="book" class="com.spring5.Book" scope="singleton">
	<property name="list" ref="bookList"></property>
</bean>

4. 生命週期

(1)通過構造器建立 bean 例項(無引數構造)
(2)為 bean 的屬性設定值和對其他 bean 引用(呼叫 set 方法)
(3)呼叫 bean 的初始化的方法(需要進行配置初始化的方法)
(4)bean 可以使用了(物件獲取到了)
(5)當容器關閉時候,呼叫 bean 的銷燬的方法(需要進行配置銷燬的方法)

4.1 xml形式

public class Orders { 
    //無引數構造 
    public Orders() { 
        System.out.println("第一步 執行無引數構造建立 bean 例項"); 
    } 
    private String oname; 
    public void setOname(String oname) { 
        this.oname = oname; 
        System.out.println("第二步 呼叫 set 方法設定屬性值"); 
    } 
    //建立執行的初始化的方法 
    public void initMethod() { 
        System.out.println("第三步 執行初始化的方法"); 
    } 
    //建立執行的銷燬的方法 
    public void destroyMethod() { 
        System.out.println("第五步 執行銷燬的方法"); 
    } 
} 
<bean id="orders" class="com.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"> 
    <property name="oname" value="手機"></property> 
</bean> 

4.2 註解形式

@Service
public class LifeCycleDemo {
    @PostConstruct
    public void init(){
        System.out.println("init");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("destroy");
    }
}

5. 後置處理器

// (1)建立類,實現介面 BeanPostProcessor,建立後置處理器 
public class MyBeanPost implements BeanPostProcessor { 
    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
throws BeansException { 
        System.out.println("在初始化之前執行的方法"); 
        return bean; 
    } 
    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) 
throws BeansException { 
        System.out.println("在初始化之後執行的方法"); 
        return bean; 
    } 
}
<!--配置後置處理器--> 
<bean id="myBeanPost" class="com.spring5.bean.MyBeanPost"></bean>

6. 自動裝配

自動裝配是根據指定裝配規則(屬性名稱或者屬性型別),Spring 自動將匹配的屬性值進行注入

6.1 xml形式

<!-- 根據屬性名稱自動注入  -->
<!--實現自動裝配 
    bean標籤屬性 autowire,配置自動裝配 
    autowire屬性常用兩個值: 
        byName根據屬性名稱注入 ,注入值bean的 id值和類屬性名稱一樣 
        byType根據屬性型別注入 
--> 
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byName"> 
    <!--<property name="dept" ref="dept"></property>--> 
</bean> 
<bean id="dept" class="com.spring5.autowire.Dept"></bean> 

<!-- 根據屬性型別自動注入 --> 
<!--實現自動裝配 
    bean標籤屬性 autowire,配置自動裝配 
    autowire屬性常用兩個值: 
        byName根據屬性名稱注入 ,注入值bean的 id值和類屬性名稱一樣 
        byType根據屬性型別注入 
--> 
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byType"> 
    <!--<property name="dept" ref="dept"></property>--> 
</bean> 
<bean id="dept" class="com.spring5.autowire.Dept"></bean>

6.2 註解注入

參考 2.2

7. 引入外部資源

7.1 xml引入propertise

<!--引入外部屬性檔案--> 
<context:property-placeholder location="classpath:jdbc.properties"/> 

7.2 註解引入propertise

@PropertySource("classpath:jdbc.properties")
@Configuration
public class PersonAutoConfiguration {
本文由鵬鵬出品

相關文章