SSM學(xué)習(xí)之Spring

SSM-Spring框架學(xué)習(xí)

一、概念

Spring是一個輕量級的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器(框架)。

二、優(yōu)點(diǎn)

1、Spring是一個開源免費(fèi)的框架 , 容器 .

2、Spring是一個輕量級的框架 , 非侵入式的 .

3、控制反轉(zhuǎn) IoC , 面向切面 Aop

4、對事物的支持 , 對框架的支持

三、組成

3.1 Spring 框架是一個分層架構(gòu)

由 7 個定義良好的模塊組成,Spring 模塊構(gòu)建在核心容器之上,核心容器定義了創(chuàng)建、配置和管理 bean 的方式 .

圖片

3.2 組成 Spring 框架的每個模塊(或組件)都可以單獨(dú)存在:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實(shí)現(xiàn)。BeanFactory 使用控制反轉(zhuǎn)(IOC) 模式將應(yīng)用程序的配置和依賴性規(guī)范與實(shí)際的應(yīng)用程序代碼分開。

  • Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業(yè)服務(wù),例如 JNDI、EJB、電子郵件、國際化、校驗和調(diào)度功能。

  • Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向切面的編程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的對象。Spring AOP 模塊為基于 Spring 的應(yīng)用程序中的對象提供了事務(wù)管理服務(wù)。通過使用 Spring AOP,不用依賴組件,就可以將聲明性事務(wù)管理集成到應(yīng)用程序中。

  • Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結(jié)構(gòu),可用該結(jié)構(gòu)來管理異常處理和不同數(shù)據(jù)庫供應(yīng)商拋出的錯誤消息。異常層次結(jié)構(gòu)簡化了錯誤處理,并且極大地降低了需要編寫的異常代碼數(shù)量(例如打開和關(guān)閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結(jié)構(gòu)。

  • Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關(guān)系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務(wù)和 DAO 異常層次結(jié)構(gòu)。

  • Spring Web 模塊:Web 上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于 Web 的應(yīng)用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/p>

  • Spring MVC 框架:MVC 框架是一個全功能的構(gòu)建 Web 應(yīng)用程序的 MVC 實(shí)現(xiàn)。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術(shù),其中包括 JSP、Velocity、Tiles、iText 和 POI。

圖片

拓展

Spring Boot與Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置腳手架,可以基于Spring Boot 快速開發(fā)單個微服務(wù);

  • Spring Cloud是基于Spring Boot實(shí)現(xiàn)的;

  • Spring Boot專注于快速、方便集成的單個微服務(wù)個體,Spring Cloud關(guān)注全局的服務(wù)治理框架;

  • Spring Boot使用了約束優(yōu)于配置的理念,很多集成方案已經(jīng)幫你選擇好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot來實(shí)現(xiàn),Spring Boot可以離開Spring Cloud獨(dú)立使用開發(fā)項目,但是Spring Cloud離不開Spring Boot,屬于依賴的關(guān)系。

  • SpringBoot在SpringClound中起到了承上啟下的作用,如果你要學(xué)習(xí)SpringCloud必須要學(xué)習(xí)SpringBoot。

四、控制反轉(zhuǎn)(IOC)

4.1 本質(zhì)

  • 控制反轉(zhuǎn)IoC(Inversion of Control),是一種設(shè)計思想,DI(依賴注入)是實(shí)現(xiàn)IoC的一種方法

  • 控制反轉(zhuǎn)是一種通過描述(XML或注解)并通過第三方去生產(chǎn)或獲取特定對象的方式。在Spring中實(shí)現(xiàn)控制反轉(zhuǎn)的是IoC容器,其實(shí)現(xiàn)方法是依賴注入(Dependency Injection,DI)

  • IoC是Spring框架的核心內(nèi)容

    Spring容器在初始化時先讀取配置文件,根據(jù)配置文件或元數(shù)據(jù)創(chuàng)建與組織對象存入容器中,程序使用時再從Ioc容器中取出需要的對象。<在配置文件加載的時候,容器中管理的對象就已經(jīng)初始化了>

    圖片

采用XML方式配置Bean的時候,Bean的定義信息是和實(shí)現(xiàn)分離的,而采用注解的方式可以把兩者合為一體,Bean的定義信息直接以注解的形式定義在實(shí)現(xiàn)類中,從而達(dá)到了零配置的目的。

五、快速上手Spring

5.1 配置環(huán)境

導(dǎo)入Jar包

注 : spring 需要導(dǎo)入commons-logging進(jìn)行日志記錄 . 我們利用maven , 他會自動下載對應(yīng)的依賴項 (包含測試依賴).

<dependencies>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 <version>5.2.0.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.12</version>
 <scope>test</scope>
 </dependency>
</dependencies></pre>

5.2 編寫代碼

1、編寫一個Hello實(shí)體類

public class Hello {
 private String name;

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

 public void show(){
 System.out.println("Hello,"+ name );
 }
}

2、編寫我們的spring文件 , 這里我們命名為beans.xml

<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就是java對象 , 由Spring創(chuàng)建和管理-->
 <bean id="hello" class="com.kuang.pojo.Hello">
 <property name="name" value="Spring"/>
 </bean>
</beans></pre>

3、我們可以去進(jìn)行測試了 .

@Test
public void test(){
 //解析beans.xml文件 , 生成管理相應(yīng)的Bean對象
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //getBean : 參數(shù)即為spring配置文件中bean的id .
 Hello hello = (Hello) context.getBean("hello");
 hello.show();
}

思考

  • Hello 對象是誰創(chuàng)建的 ? 【hello 對象是由Spring創(chuàng)建的

  • Hello 對象的屬性是怎么設(shè)置的 ? hello 對象的屬性是由Spring容器設(shè)置的

這個過程就叫控制反轉(zhuǎn) :

  • 控制 : 誰來控制對象的創(chuàng)建 , 傳統(tǒng)應(yīng)用程序的對象是由程序本身控制創(chuàng)建的 , 使用Spring后 , 對象是由Spring來創(chuàng)建的

  • 反轉(zhuǎn) : 程序本身不創(chuàng)建對象 , 而變成被動的接收對象 .

依賴注入 : 就是利用set方法來進(jìn)行注入的.

IOC是一種編程思想,由主動的編程變成被動的接收

可以通過newClassPathXmlApplicationContext去瀏覽一下底層源碼 .

5.3 IOC創(chuàng)建對象方式

5.3.1 通過無參構(gòu)造方法來創(chuàng)建

1、User.java

public class User {

 private String name;

 public User() {
 System.out.println("user無參構(gòu)造方法");
 }

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

 public void show(){
 System.out.println("name="+ name );
 }

}

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">

 <bean id="user" class="com.kuang.pojo.User">
 <property name="name" value="kuangshen"/>
 </bean>

</beans>

3、測試類

@Test
public void test(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //在執(zhí)行g(shù)etBean的時候, user已經(jīng)創(chuàng)建好了 , 通過無參構(gòu)造
 User user = (User) context.getBean("user");
 //調(diào)用對象的方法 .
 user.show();
}

結(jié)果可以發(fā)現(xiàn),在調(diào)用show方法之前,User對象已經(jīng)通過無參構(gòu)造初始化了!

5.3.2 通過有參構(gòu)造方法來創(chuàng)建

1、UserT . java

public class UserT {

 private String name;

 public UserT(String name) {
 this.name = name;
 }

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

 public void show(){
 System.out.println("name="+ name );
 }

}

2、beans.xml 有三種方式編寫

<!-- 第一種根據(jù)index參數(shù)下標(biāo)設(shè)置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- index指構(gòu)造方法 , 下標(biāo)從0開始 -->
   <constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二種根據(jù)參數(shù)名字設(shè)置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- name指參數(shù)名 -->
   <constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三種根據(jù)參數(shù)類型設(shè)置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>

3、測試

@Test
public void testT(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 UserT user = (UserT) context.getBean("userT");
 user.show();
}

結(jié)論:在配置文件加載的時候。其中管理的對象都已經(jīng)初始化了!

六、Spring配置

6.1 別名

alias 設(shè)置別名 , 為bean設(shè)置別名 , 可以設(shè)置多個別名

<!--設(shè)置別名:在獲取Bean的時候可以使用別名獲取-->
<alias name="userT" alias="userNew"/>

6.2 Bean的配置

<!--bean就是java對象,由Spring創(chuàng)建和管理-->

<!--
 id 是bean的標(biāo)識符,要唯一,如果沒有配置id,name就是默認(rèn)標(biāo)識符
 如果配置id,又配置了name,那么name是別名
 name可以設(shè)置多個別名,可以用逗號,分號,空格隔開
 如果不配置id和name,可以根據(jù)applicationContext.getBean(.class)獲取對象;

class是bean的全限定名=包名+類名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
 <property name="name" value="Spring"/>
</bean>

6.3 import

團(tuán)隊的合作通過import來實(shí)現(xiàn) .

七、依賴注入(DI)

7.1 概念

  • 依賴注入(Dependency Injection,DI)。

  • 依賴 : 指Bean對象的創(chuàng)建依賴于容器 . Bean對象的依賴資源 .

  • 注入 : 指Bean對象所依賴的資源 , 由容器來設(shè)置和裝配 .

7.2 Set注入

要求被注入的屬性 , 必須有set方法 , set方法的方法名由set + 屬性首字母大寫 , 如果屬性是boolean類型 , 沒有set方法 , 是 is .

測試pojo類 :

Address.java

 public class Address {

     private String address;

     public String getAddress() {
         return address;
    }

     public void setAddress(String address) {
         this.address = address;
    }
 }

Student.java

package com.kuang.pojo;

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

 public class Student {

     private String name;
     private Address address;
     private String[] books;
     private List<String> hobbys;
     private Map<String,String> card;
     private Set<String> games;
     private String wife;
     private Properties info;

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

     public void setAddress(Address address) {
         this.address = address;
    }

     public void setBooks(String[] books) {
         this.books = books;
    }

     public void setHobbys(List<String> hobbys) {
         this.hobbys = hobbys;
    }

     public void setCard(Map<String, String> card) {
         this.card = card;
    }

     public void setGames(Set<String> games) {
         this.games = games;
    }

     public void setWife(String wife) {
         this.wife = wife;
    }

     public void setInfo(Properties info) {
         this.info = info;
    }

     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n愛好:"+hobbys);

         System.out.println("card:"+card);

         System.out.println("games:"+games);

         System.out.println("wife:"+wife);

         System.out.println("info:"+info);

    }
 }

7.2.1 常量注入

<bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
 </bean></pre>

測試:

@Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

     Student student = (Student) context.getBean("student");

     System.out.println(student.getName());

 }

7.2.2 Bean注入

注意點(diǎn):這里的值是一個引用,ref

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

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
 </bean>

7.2.3 數(shù)組注入

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
     <property name="books">
         <array>
             <value>西游記</value>
             <value>紅樓夢</value>
             <value>水滸傳</value>
         </array>
     </property>
 </bean>

7.2.4 List注入

 <property name="hobbys">
 <list>
 <value>聽歌</value>
 <value>看電影</value>
 <value>爬山</value>
 </list>
 </property>

7.2.5 Map注入

<property name="card">
 <map>
 <entry key="中國郵政" value="456456456465456"/>
 <entry key="建設(shè)" value="1456682255511"/>
 </map>
 </property>

7.2.6 set注入

 <property name="games">
 <set>
 <value>LOL</value>
 <value>BOB</value>
 <value>COC</value>
 </set>
 </property>

7.2.7 Null注入

<property name="wife"><null/></property>

7.2.8 Properties注入

<property name="info">
 <props>
 <prop key="學(xué)號">20190604</prop>
 <prop key="性別">男</prop>
 <prop key="姓名">小明</prop>
 </props>
 </property>

擴(kuò)展:Properties和Map都是以鍵值對的形式存儲的,但是他們有什么區(qū)別嗎?

最大的區(qū)別就是 Properties可以直接導(dǎo)入IO流 讀取IO流中的數(shù)據(jù) 并且能把自己的元素輸出到IO流中。就是我們可以去寫properties文件,進(jìn)行讀寫。

7.3 p命名和c命名注入

7.3.1 P命名空間注入 : 需要在頭文件中加入約束文件

導(dǎo)入約束 : xmlns:p="http://www.springframework.org/schema/p"

 <!--P(屬性: properties)命名空間 , 屬性依然要設(shè)置set方法-->
 <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>

7.3.2 c 命名空間注入 : 需要在頭文件中加入約束文件

導(dǎo)入約束 : xmlns:c="http://www.springframework.org/schema/c"
 <!--C(構(gòu)造: Constructor)命名空間 , 屬性依然要設(shè)置set方法-->
 <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

7.4 Bean的作用域

在Spring中,那些組成應(yīng)用程序的主體及由Spring IoC容器所管理的對象,被稱之為bean。簡單地講,bean就是由IoC容器初始化、裝配及管理的對象 .

圖片

7.4.1 Singleton

當(dāng)一個bean的作用域為Singleton,那么Spring IoC容器中只會存在一個共享的bean實(shí)例,并且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實(shí)例。

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton"

7.4.2 Prototype

當(dāng)一個bean的作用域為Prototype,表示一個bean定義對應(yīng)多個對象實(shí)例。Prototype作用域的bean會導(dǎo)致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調(diào)用容器的getBean()方法)時都會創(chuàng)建一個新的bean實(shí)例。Prototype是原型類型,它在我們創(chuàng)建容器的時候并沒有實(shí)例化,而是當(dāng)我們獲取bean的時候才會去創(chuàng)建一個對象,而且我們每次獲取到的對象都不是同一個對象。

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
 或者
 <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

對有狀態(tài)的bean應(yīng)該使用prototype作用域,而對無狀態(tài)的bean則應(yīng)該使用singleton作用域

補(bǔ)充:scope中單例(singleton)和prototype的優(yōu)缺點(diǎn):

singleton(默認(rèn)):優(yōu)點(diǎn):不會new對象,節(jié)省資源;缺點(diǎn):在處理高并發(fā)的時候可能會延遲或數(shù)據(jù)不一致 prototype:優(yōu)點(diǎn):多線程穩(wěn)定 缺點(diǎn):每次在創(chuàng)建浪費(fèi)資源 多線程使用prototype,單線程使用singleton

7.4.3 Request

當(dāng)一個bean的作用域為Request,表示在一次HTTP請求中,一個bean定義對應(yīng)一個實(shí)例。即每個HTTP請求都會有各自的bean實(shí)例,它們依據(jù)某個bean定義創(chuàng)建而成。

針對每次HTTP請求,Spring容器會根據(jù)loginAction bean的定義創(chuàng)建一個全新的LoginAction bean實(shí)例,且該loginAction bean實(shí)例僅在當(dāng)前HTTP request內(nèi)有效。當(dāng)處理請求結(jié)束,request作用域的bean實(shí)例將被銷毀。

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

7.4.3 Session

當(dāng)一個bean的作用域為Session,表示在一個HTTP Session中,一個bean定義對應(yīng)一個實(shí)例。該作用域僅在基于web的Spring ApplicationContext情形下有效。

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

針對某個HTTP Session,Spring容器會根據(jù)userPreferences bean定義創(chuàng)建一個全新的userPreferences bean實(shí)例,且該userPreferences bean僅在當(dāng)前HTTP Session內(nèi)有效.

八、自動裝配

8.1 概念

  • 自動裝配是使用spring滿足bean依賴的一種方法

  • spring會在應(yīng)用上下文中為某個bean尋找其依賴的bean。

8.2 裝配機(jī)制

Spring中bean有三種裝配機(jī)制,分別是:

  1. 在xml中顯式配置;

  2. 在java中顯式配置;

  3. 隱式的bean發(fā)現(xiàn)機(jī)制和自動裝配。

8.3 實(shí)現(xiàn)

Spring的自動裝配需要從兩個角度來實(shí)現(xiàn),或者說是兩個操作:

  1. 組件掃描(component scanning):spring會自動發(fā)現(xiàn)應(yīng)用上下文中所創(chuàng)建的bean;

  2. 自動裝配(autowiring):spring自動滿足bean之間的依賴,也就是我們說的IoC/DI;

1、新建一個項目

2、新建兩個實(shí)體類,Cat Dog 都有一個叫的方法

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

3、新建一個用戶類 User

public class User {
 private Cat cat;
 private Dog dog;
 private String str;
}

4、編寫Spring配置文件

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

 <bean id="user" class="com.kuang.pojo.User">
 <property name="cat" ref="cat"/>
 <property name="dog" ref="dog"/>
 <property name="str" value="qinjiang"/>
 </bean>
</beans>

5、測試

public class MyTest {
 @Test
 public void testMethodAutowire() {
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 User user = (User) context.getBean("user");
 user.getCat().shout();
 user.getDog().shout();
 }
}

8.3.1 autowire byName (按名稱自動裝配)

由于在手動配置xml過程中,常常發(fā)生字母缺漏和大小寫等錯誤,而無法對其進(jìn)行檢查,使得開發(fā)效率降低。

采用自動裝配將避免這些錯誤,并且使配置簡單化。

測試:

1、修改bean配置,增加一個屬性 autowire="byName"

<bean id="user" class="com.kuang.pojo.User" autowire="byName">
 <property name="str" value="qinjiang"/>
</bean>

2、再次測試,結(jié)果依舊成功輸出!

3、我們將 cat 的bean id修改為 catXXX

4、再次測試, 執(zhí)行時報空指針java.lang.NullPointerException。因為按byName規(guī)則找不對應(yīng)set方法,真正的setCat就沒執(zhí)行,對象就沒有初始化,所以調(diào)用時就會報空指針錯誤。

小結(jié):

當(dāng)一個bean節(jié)點(diǎn)帶有 autowire byName的屬性時。

  1. 將查找其類中所有的set方法名,例如setCat,獲得將set去掉并且首字母小寫的字符串,即cat。

  2. 去spring容器中尋找是否有此字符串名稱id的對象。

  3. 如果有,就取出注入;如果沒有,就報空指針異常。

8.3.2 autowire byType (按類型自動裝配)

使用autowire byType首先需要保證:同一類型的對象,在spring容器中唯一。如果不唯一,會報不唯一的異常。NoUniqueBeanDefinitionException

測試:

1、將user的bean配置修改一下 : autowire="byType"

2、測試,正常輸出

3、在注冊一個cat 的bean對象!

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User" autowire="byType">
 <property name="str" value="qinjiang"/>
</bean>

4、測試,報錯:NoUniqueBeanDefinitionException

5、刪掉cat2,將cat的bean名稱改掉!測試!因為是按類型裝配,所以并不會報異常,也不影響最后的結(jié)果。甚至將id屬性去掉,也不影響結(jié)果。

九、使用注解

9.1 配置

jdk1.5開始支持注解,spring2.5開始全面支持注解。

準(zhǔn)備工作:利用注解的方式注入屬性。

1、在spring配置文件中引入context文件頭

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

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

2、開啟屬性注解支持!

<context:annotation-config/>

9.2 @Autowired

  • @Autowired是按類型自動轉(zhuǎn)配的,不支持id匹配。

  • 需要導(dǎo)入 spring-aop的包!

測試:

1、將User類中的set方法去掉,使用@Autowired注解

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

2、此時配置文件內(nèi)容

<context:annotation-config/>

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>

3、測試,成功輸出結(jié)果!

【補(bǔ)充】

@Autowired(required=false) 說明:false,對象可以為null;true,對象必須存對象,不能為null。

//如果允許對象為null,設(shè)置required = false,默認(rèn)為true
@Autowired(required = false)
private Cat cat;

9.3 @Qualifier

  • @Autowired是根據(jù)類型自動裝配的,加上@Qualifier則可以根據(jù)byName的方式自動裝配

  • @Qualifier不能單獨(dú)使用。

測試實(shí)驗步驟:

1、配置文件修改內(nèi)容,保證類型存在對象。且名字不為類的默認(rèn)名字!

<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

2、沒有加Qualifier測試,直接報錯

3、在屬性上添加Qualifier注解

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

測試,成功輸出!

9.4 @Resource

  • @Resource如有指定的name屬性,先按該屬性進(jìn)行byName方式查找裝配;

  • 其次再進(jìn)行默認(rèn)的byName方式進(jìn)行裝配;

  • 如果以上都不成功,則按byType的方式自動裝配。

  • 都不成功,則報異常。

實(shí)體類:

public class User {
   //如果允許對象為null,設(shè)置required = false,默認(rèn)為true
   @Resource(name = "cat2")
   private Cat cat;
   @Resource
   private Dog dog;
   private String str;
}

beans.xml

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User"/>

測試:結(jié)果OK

配置文件2:beans.xml , 刪掉cat2

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>

實(shí)體類上只保留注解

@Resource
private Cat cat;
@Resource
private Dog dog;

結(jié)果:OK

結(jié)論:先進(jìn)行byName查找,失敗;再進(jìn)行byType查找,成功。

9.5 @Nullable <補(bǔ)充>

字段標(biāo)記了這個注解,說明這個字段可以為null

小結(jié)

@Autowired與@Resource異同:

1、@Autowired與@Resource都可以用來裝配bean。都可以寫在字段上,或?qū)懺趕etter方法上。

2、@Autowired默認(rèn)按類型裝配(屬于spring規(guī)范),默認(rèn)情況下必須要求依賴對象必須存在,如果要允許null 值,可以設(shè)置它的required屬性為false,如:@Autowired(required=false) ,如果我們想使用名稱裝配可以結(jié)合@Qualifier注解進(jìn)行使用

3、@Resource(屬于J2EE復(fù)返),默認(rèn)按照名稱進(jìn)行裝配,名稱可以通過name屬性進(jìn)行指定。如果沒有指定name屬性,當(dāng)注解寫在字段上時,默認(rèn)取字段名進(jìn)行按照名稱查找,如果注解寫在setter方法上默認(rèn)取屬性名進(jìn)行裝配。當(dāng)找不到與名稱匹配的bean時才按照類型進(jìn)行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進(jìn)行裝配。

它們的作用相同都是用注解方式注入對象,但執(zhí)行順序不同。@Autowired先byType,@Resource先byName。

十、使用注解開發(fā)

10.1 配置

在spring4之后,想要使用注解形式,必須得要引入aop的包

圖片

在配置文件當(dāng)中,還得要引入一個context約束

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

10.2 bean的實(shí)現(xiàn)

1、配置掃描哪些包下的注解

<!--指定注解掃描包-->
<context:component-scan base-package="com.kuang.pojo"/>

2、在指定包下編寫類,增加注解

@Component("user")
// 相當(dāng)于配置文件中 <bean id="user" class="當(dāng)前注解的類"/>
public class User {
   public String name = "alen";
}

3、測試

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}

10.3 屬性注入

使用注解注入屬性

1、可以不用提供set方法,直接在直接名上添加@value("值")

@Component("user")
// 相當(dāng)于配置文件中 <bean id="user" class="當(dāng)前注解的類"/>
public class User {
   @Value("alen")
   // 相當(dāng)于配置文件中 <property name="name" value="alen"/>
   public String name;
}

2、如果提供了set方法,在set方法上添加@value("值");

@Component("user")
public class User {

   public String name;

   @Value("alen")
   public void setName(String name) {
       this.name = name;
  }
}

10.4 衍生注解

@Component三個衍生注解

為了更好的進(jìn)行分層,Spring可以使用其它三個注解,功能一樣,目前使用哪一個功能都一樣。

  • @Controller:web層

  • @Service:service層

  • @Repository:dao層

寫上這些注解,就相當(dāng)于將這個類交給Spring管理裝配了!

10.5 作用域

@scope

  • singleton:默認(rèn)的,Spring會采用單例模式創(chuàng)建這個對象。關(guān)閉工廠 ,所有的對象都會銷毀。

  • prototype:多例模式。關(guān)閉工廠 ,所有的對象不會銷毀。內(nèi)部的垃圾回收機(jī)制會回收

@Controller("user")
@Scope("prototype")
public class User {
   @Value("alen")
   public String name;
}

小結(jié):

XML與注解比較

  • XML可以適用任何場景 ,結(jié)構(gòu)清晰,維護(hù)方便

  • 注解不是自己提供的類使用不了,開發(fā)簡單方便

xml與注解整合開發(fā) :推薦最佳實(shí)踐

  • xml管理Bean

  • 注解完成屬性注入

  • 使用過程中, 可以不用掃描,掃描是為了類上的注解

<context:annotation-config/>

作用:

  • 進(jìn)行注解驅(qū)動注冊,從而使注解生效

  • 用于激活那些已經(jīng)在spring容器里注冊過的bean上面的注解,也就是顯示的向Spring注冊

  • 如果不掃描包,就需要手動配置bean

  • 如果不加注解驅(qū)動,則注入的值為null!

10.6 基于Java類進(jìn)行配置

JavaConfig 原來是 Spring 的一個子項目,它通過 Java 類的方式提供 Bean 的定義信息,在 Spring4 的版本, JavaConfig 已正式成為 Spring4 的核心功能 。

測試:

1、編寫一個實(shí)體類,Dog

@Component  //將這個類標(biāo)注為Spring的一個組件,放到容器中!
public class Dog {
   public String name = "dog";
}

2、新建一個config配置包,編寫一個MyConfig配置類

@Configuration  //代表這是一個配置類
public class MyConfig {

   @Bean //通過方法注冊一個bean,這里的返回值就Bean的類型,方法名就是bean的id!
   public Dog dog(){
       return new Dog();
  }

}

3、測試

@Test
public void test2(){
   ApplicationContext applicationContext =
           new AnnotationConfigApplicationContext(MyConfig.class);
   Dog dog = (Dog) applicationContext.getBean("dog");
   System.out.println(dog.name);
}

導(dǎo)入其他配置如何做呢?

1、我們再編寫一個配置類!

@Configuration  //代表這是一個配置類
public class MyConfig2 {
}

2、在之前的配置類中我們來選擇導(dǎo)入這個配置類

@Configuration
@Import(MyConfig2.class)  //導(dǎo)入合并其他配置類,類似于配置文件中的 inculde 標(biāo)簽
public class MyConfig {

   @Bean
   public Dog dog(){
       return new Dog();
  }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容