工廠只負責建立對象,而Spring固然不只僅是一個對象工廠,其核心是一個對象容器,其具有控制反轉的能力,因此也稱爲IOC容器。java
幫助咱們存放對象,而且管理對象,包括:建立、銷燬、裝配,這樣就將本來由程序本身完成的工做,交給了框架來完成,稱爲IOC容器。web
學習的核心也就在於如何將對象放在Spring中,以及如何從Spring中取出來。面試
ApplicationContext
BeanFactory
ApplicationContext是BeanFactory的子接口,它們均可以做爲Spring的容器。正則表達式
區別:spring
BeanFactory採起懶加載方式(會有延遲),在獲取對象時纔會實例化
ApplicationContext在工廠初始化時當即實例化對象
BeanFactory做爲頂級接口主要面向於Spring框架自己,僅提供了基本的容器功能,如DI
ApplicationContext時BeanFactory的子接口,意味着功能比BeanFactory更多,諸如國際化(根據用戶的地理位置對產品的表現形式進行一些變化,例如文字、樣式),註解配置,XML配置等等,所以ApplicationContext使用更多
ApplicationContext的個實現類的區別:
ClassPath表示從類路徑獲取配置文件
FileSystem表示從文件系統獲取配置文件api
1.建立一個maven項目
2.配置mavensession
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!-- Maven會自動下載全部Spring核心容器和aop的依賴--> </dependencies>
3.在resource下建立一個名爲applicationContext.xml的配置文件app
自動生成:在這裏配置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.xsd"> </beans>
4.建立contoller、service對應的包maven
準備工做已完成,下面書寫Bean實例化的方式
使用該方式時,Bean類中必需要有無參構造
<!--使用無參構造實例化Bean--> <bean id="userService" class="cx.service.UserServiceImpl" />
測試
public class UserController { private UserService service; public UserController() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //經過指定文件路徑加載Spring配置文件,通常不多用 //FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("D:\\ideaProject\\SpringDemo2\\src\\main\\resources\\applicationContext.xml"); //根據id或name獲取 service = (UserService) context.getBean("userService"); //經過接口類來獲取 //service = context.getBean(UserService.class); //經過具體類來獲取 //service = context.getBean(UserServiceImpl.class); } public void say(){ service.say(); } public static void main(String[] args) { new UserController().say(); } }
建立一個工廠類
public class factory { public static UserService getService(){ System.out.println("執行了靜態工廠方法"); return new UserServiceImpl(); } }
xml配置
<!--使用靜態工廠方式--> <bean id="userService2" class="cx.service.factory" factory-method="getService"/>
xml文件
<!--經過實例工廠方式 工廠Bean--> <bean id="factory" class="cx.service.factory" /> <!--配置userService 調用factory 指定getService2 指定使用的工廠對象時哪個--> <bean id="userService3" factory-bean="factory" factory-method="getService2" />
調用:
service = (UserService) context.getBean("userService3");
首先需配置工廠類,而後經過factory-bean調用剛剛命名的那個Bean,寫入id,用factory-method指定要使用的工廠的方法。
配置Bean時,可使用 id 或者 name 屬性給bean命名。 id 和 name 屬性做用上同樣,推薦使用id。
id取值要求嚴格些,必須知足XML的命名規範。id是惟一的,配置文件中不容許出現兩個id相同的bean。
name取值比較隨意,甚至能夠用數字開頭。在配置文件中容許出現多個name相同的bean,在用getBean()返回實例時,最後的一個Bean將被返回。
注意:在spring5中name和id同樣也不容許有重複的名稱。
若是沒有id,name,則默認使用類的全名做爲name,如 ,<bean class="com.cx.service.UserService"/>可使用 getBean(「com.cx.service.UserService」)返回該實例。
若是存在多個id和name都沒有指定,且類都同樣的,如:
則能夠經過getBean(「完整類名#索引」)來得到,如:getBean(「com.cx.service.UserService#1」),索引從0開始,若要獲取第一個則能夠忽略索引,直接寫類名。
name中可使用分號(「;」)、空格(「 」)或逗號(「,」)來給這個Bean添加多個名稱(至關於別名 alias 的做用)。如:name=「a b c d」等同於 name=「a,b,c,d」 這樣寫至關於有 1 2 3 4(4個)個標識符標識當前bean ,而id中的任何字符都被做爲一個總體 ;
若是既配置了 id ,也配置了 name ,則兩個都生效。固然也不能重複;
當註解中出現與xml配置中相同的id或相同name時,優先使用xml中的配置
類別 說明
做用域就是指做用範圍:
單例則表示對象的做用範圍是整個Spring容器,
而prototype則表示無論理做用範圍,每次get就直接建立新的。
request、session和 application三種做用域僅在基於web的應用中使用
init和destory
Spring提供了非***(不強制類繼承或實現)方式的生命週期方法,能夠在Bean的初始化以及銷燬時作一些額外的操做
<!--init-method 用於初始化操做的方法 destroy-method 用於銷燬操做的方法 這兩個都是指定方法名--> <bean id="userService" class="cx.service.UserServiceImpl" scope="singleton" init-method="init" destroy-method="destroy"/>
注意:
destroy僅僅在scope爲singleton時有效
1 構造對象
2 設置屬性
3 瞭解Bean在容器中的name
4 瞭解關聯的beanFactory
5 初始化前處理
6 屬性設置完成
7 自定義初始化方法
8 初始化後處理
9 業務方法
10 Bean銷燬方法
11 自定義銷燬方法
依賴指的是檔期啊對象在運行過程當中須要使用到的其餘參數或者對象;
Spring能夠幫助咱們完成這個依賴關係的創建;
說的簡單點即把你須要的參數給你,而你無論參數是怎麼來的,只管用便可,以達到儘量地解耦。
for example
controller中須要service對象,Spring能夠把service自動丟到controller中,你不須要關注service對象是怎麼來的,用就能夠了
要使用依賴注入,必須先在須要依賴的一方(controller)中爲被依賴的一方(service)定義屬性,用於接收注入;
bean:
書寫user
public class User { private Integer id; private String name; private String sex; private PC pc; }
還有有參/無參構造,getter/setter方法,以及toString
user中須要的pc類
public class PC { private String model; }
在applicationContext.xml中注入,構造方法注入
<!--依賴注入構造方法注入--> <bean id="user" class="cx.pojo.User"> <!--按參數名稱注入--> <constructor-arg name="id" value="1"/> <!--按參數位置注入--> <constructor-arg index="1" value="張三"/> <constructor-arg index="2" value="男" /> <!--參數類型爲其餘bean對象時,value換爲ref--> <constructor-arg index="3" ref="pc"/> </bean> <bean id="pc" class="cx.pojo.PC"> <constructor-arg index="0" value="小米"/> </bean>
測試代碼:
public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) context.getBean("user"); System.out.println(user); } public static void main(String[] args) { new TestController().test1(); }
在上述中,還可使用下述注入
<!--使用setter方法注入(屬性注入)--> <bean id="user2" class="cx.pojo.User"> <property name="id" value="2"/> <property name="name" value="李四"/> <property name="sex" value="男"/> <property name="pc" ref="pc" /> </bean>
注意:setter方法注入配置要求User中必須有無參構造方法
上面的兩種依賴注入方法,若是在須要注入的依賴較多時致使xml顯得很臃腫,C名稱空間來簡化xml中標籤的書寫。
須要先在xml中進行聲明
xmlns:c="http://www.springframework.org/schema/c"
使用:
<!--c命名空間的使用--> <!--c:id 指定爲id參數賦值 c:_1 指定爲構造函數的第2個參數賦值 c:p-ref 指定爲構造函數的pc參數賦值爲id爲"pc"的Bean --> <bean id="user3" class="cx.pojo.User" c:id="3" c:_1="王五" c:_2="男" c:pc-ref="pc" />
同理p命名標籤也須要在xml中進行聲明
xmlns:p="http://www.springframework.org/schema/p" ``` 使用: ```java <!--p:id 指定爲id屬性賦值 p:name name屬性賦值 p:sex sex屬性賦值 p:pc-ref 爲pc屬性賦值爲id爲"pc"的Bean--> <bean id="user4" class="cx.pojo.User" p:id="4" p:name="趙六" p:sex="女" p:pc-ref="pc"/>
SpEL即Spring Expression Language的縮寫,與JSTL同樣是表達式語言,能夠支持使用更加複雜的語法注入依賴,包括標準數學運算符,關係運算符,邏輯運算符,條件運算符,集合和正則表達式等;
語法: #{表達式}
用例:
<!--SpEL --> <bean id="user" class="com.cx.pojo.User"> <!--<property name="name" value="#{'cx'}"/>--> <!--字符常量--> <!--<property name="age" value="#{100.0}"/>--> <!--數字常量--> <!--<property name="phone" value="#{phone}"/>--> <!--對象引用--> <!--<property name="name" value="#{phone.model.concat(' cx')}"/>--> <!--方法調用--> <!--<property name="age" value="#{1+100}"/>--> <!--算數符--> <!--<property name="name" value="#{1>100}"/>--> <!--比較符--> <!--<property name="name" value="#{true or false}"/>--> <!--邏輯符--> <!--<property name="name" value="#{1 > 0?1:0}"/>--> <!--三目--> </bean>
xml:
<bean id="userdemo" class="com.lbb.pojo.UserDemo"> <!--注入set--> <property name="set"> <set> <value>1</value> <value>2</value> <value>3</value> <value>4</value> </set> </property> <!--注入list--> <property name="list"> <list> <value>1</value> <value>2</value> <value>3</value> <value>4</value> </list> </property> <!--注入map--> <property name="map"> <map> <entry key="1" value="1"/> <entry key="2" value="2"/> <entry key="3" value="3"/> <entry key="4" value="4"/> </map> </property> <!--注入properties--> <property name="properties"> <props> <prop key="1">1</prop> <prop key="2">2</prop> <prop key="3">3</prop> <prop key="4">4</prop> </props> </property> </bean>
上述寫法一樣適用於構造函數注入:
<bean class="service.Person"> <constructor-arg name="name" value="jerry"/> <constructor-arg name="properties"> <props> <prop key="pwd">123</prop> </props> </constructor-arg> </bean>
強調:java Spring的依賴注入要麼經過構造函數,要麼經過setter
接口注入不是一種注入方式,只不過因爲OOP的多態,Spring在按照類型注入時,會在容器中查找類型匹配的Bean,若是沒有則查找該類的子類,若是容器中有多個匹配的子類Bean時會拋出異常。
註解配置Bean
通用註解
@Component 用於在Spring中加入Bean
MVC場景下
@Controller 等價於 @Component 標註控制層
@Service 等價於 @Component 標註業務層
@Repository 等價於 @Component 標註數據訪問層(DAO)
在實現上暫時沒有任何不一樣,在底層源碼裏就是給Component取了別名,僅僅是爲了對Bean進行分層是結構更清晰
1.須要依賴context和aop兩個jar包
2.配置applicationContext.xml
添加命名空間(idea下 輸入<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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--指定要掃描註解的包 會自動掃描子包 --> <context:component-scan base-package="com.cx.pojo"/> </beans>
要註冊的Bean
@Component public class User { private Integer id; private String name; private String sex; private PC pc; }
測試代碼
public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) context.getBean("user"); System.out.println(user); }
若是註解中沒有指定id,則默認使用簡單類名且小寫開頭,例如:上述的user。
註解注入br/>@value用於對基本類型的注入
@Autowired將容器中的其餘Bean注入到屬性中,自動裝配br/>@Qualifier(「BeanId」)指定要注入的Bean的Id,須要和Autowired一塊兒使用
@Resource 至關於: @Autowired 和@Qualifier 一塊兒使用.
@value
@Value("12") private int age; @Value("tom") private String name; @Value("#{1+2+3}") private String pwd;
@Value("${jdbc.user}") //注入屬性配置 private String user;
上述注入屬性配置使用${}取配置文件裏面的值:
首先須要加載配置文件,在applicationContext.xml加入:
<context:property-placeholder location="jdbc.properties"/>
@Autowired
自動注入一個Bean,默認按照類型來注入
required屬性用於設置屬性是不是必須的默認爲true,若是爲true找不到會報錯,若是false則會爲空,不會報錯
使用:
User 類:
@Component public class User { @Value("1") private Integer id; @Value("cc") private String name; @Value("男") private String sex; @Value("小米") private PC pc; }
dao層:
@Repository public class PersonDao { public void smile(){ System.out.println("ta笑了"); } }
service實現層:
@Service public class PerSonServiceImpl implements PersonService { @Autowired private PersonDao personDao; public void smile(){ personDao.smile(); } }
接口層
public interface PersonService { public void smile(); }
controller層
@Controller public class PersonController { @Autowired private PersonService personService; public void smile() { personService.smile(); } }
測試:
@Test public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); PersonController bean = context.getBean(PersonController.class); bean.smile(); }
@Qualifier
當咱們須要指定注入的bean的id時,Autowired不能配置,這時候要和Qualifier一塊兒使用,用於明確指定要注入的Bean的ID(注意必定要一塊兒使用)
使用:
上面PersonService能夠這樣寫:
@Service public class PerSonServiceImpl implements PersonService { @Autowired @Qualifier("personDaoImpl") private PersonDao personDao; public void smile(){ personDao.smile(); } }
注意:
若經過類型注入,則當Spring中存在多個類型都匹配的Bean時直接報錯,演示以下:
接口:
public interface PersonDao { }
兩個實現類:
@Repository() public class PersonDaoImpl1 implements PersonDao{ }
@Repository() public class PersonDaoImpl2 implements PersonDao{ }
3
注入:
@Component public class UserService { @Autowired private PersonDao personDao; }
這時候就會報錯,若是要這樣用必須指定Bean的name,經過name來區分。
@Resource
Qualifier和Autowired書寫繁瑣,@Resource可將兩個標籤的功能整合,即注入指定ID的Bean:
@Resource標準註解是java註解,可是在jdk中沒有導入,要配置導入,在pom.xml配置:
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
註解:
Resource默認按照使用屬性名稱做爲name查找,查找失敗則使用類型查找
能夠利用name屬性指定要查找的id
也可經過type指定類型,當出現相同類型的多個Bean時拋出異常
@Service public class PerSonServiceImpl implements PersonService { @Resource(name = "personDaoImpl") private PersonDao personDao; public void smile(){ personDao.smile(); } }
Resource能夠設置name,也能夠設置type.若是不設置的話,會先按照類型找,找不到會再按照屬性名來尋找。
Scope
用於標註Bean的做用域
@Repository() @Scope("prototype") //每次get都建立新的 public class PersonDao { public void smile(){ System.out.println("笑了"); } }
由於註解的表達能力有限,不少時候沒法知足使用需求;咱們能夠將註解和XML配合使用,讓XML負責管理Bean,註解僅負責依賴注入;
與註解掃描的不一樣之處,註解掃描用於將Bean放入容器中同時進行依賴注入,然後者僅僅是在已存在的Bean中進行依賴注入;
配置applicationContext.xml文件,開啓註解:
<!--使用xml默認是不掃描註解的,因此要配置下面開啓註解--> <context:annotation-config/>
當配置文件中的內容過可能是不便於維護,Spring支持多配置文件
方法1:
在初始化容器時指定要加載的全部配置文件
@Test public void test3(){ //讀取配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml"); //獲取bean PersonController personController= (PersonController) context.getBean("personController"); personController.smile(); }
方法2:
在配置文件中使用import來引入其餘的配置文件
<import resource="applicationContext2.xml"/>
import 裏的其餘寫法:
前綴 含義
classpath: 從classpath加載第一個匹配的文件
classpath*: 從classpath加載全部匹配的文件(用於成功分爲多個jar包時)
file: 按絕對路徑加載文件
http: 按URL路徑加載文件
最後來一波~~
基於XML配置
Bean的實例化:<bean id="" class="" />br/>Bean的命名:經過id或name指定
Bean的注入:構造方法或setter方法注入(p或c命名標籤)
生命週期,Bean的做用範圍:init-method,destroy-method,圍scope屬性,destroy僅僅在scope爲singleton時有效
使用場景:Bean來自於第三方
基於註解配置
Bean的實例化:@component、@Controller、@Service、@Repository
Bean的命名:@component(「name")br/>Bean的注入:@AutoWired按類型注入、@Qualifier按名稱注入生命週期,Bean的做用範圍:@PostConstruct初始化、@PreDestroy銷燬、@Scope設置做用範圍使用場景:Bean的實現由本身開發