Spring從入門到源碼之IOC基本用法
1、spring_helloworld
使用maven的方式來構建項目(Mavaen)
添加對應的pom依賴
pom.xml
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> </dependencies>
編寫代碼
Person.java
public class Person { private int id; private String name; private int age; private String gender; public int getId() { return id; } public void setId(int id) { this.id = id; public String getName() { return name; public void setName(String name) { this.name = name; public int getAge() { return age; public void setAge(int age) { this.age = age; public String getGender() { return gender; public void setGender(String gender) { this.gender = gender; @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + '}'; }
測試
MyTest.java
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml"); Person person = (Person) context.getBean("person"); System.out.println(person); } }
總結:
一定要將配置文件添加到類路徑中,使用idea創建項目的時候要放在resource目錄下創建對象給屬性賦值的時候是通過setter方法實現的對象在IOC容器中存儲的時候都是單例的,如果需要多例需要修改屬性(默認單例,可以改多例)對象在Spring容器創建完成的時候就已經創建完成,不是需要用的時候才創建(Application創建時候對象就創建瞭)ApplicationContext就是IOC容器的接口,可以通過此對象獲取容器中創建的對象
2、spring對象的獲取及屬性賦值方式
1、通過bean的id獲取IOC容器中的對象(上面已經用過)
<?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"> <!-- id 對象唯一標識 class 類名字:完全限定名字 --> <bean id = "person" class="com.yao.bean.Person"> <property name="id" value="001"/> <property name="name" value="yzh"/> <property name="age" value="12"/> <property name="gender" value="man"/> </bean> </beans>
- 一定要將配置文件添加到類路徑中,使用idea創建項目的時候要放在resource目錄下
- 創建對象給屬性賦值的時候是通過setter方法實現的
- 對象在IOC容器中存儲的時候都是單例的,如果需要多例需要修改屬性(默認單例,可以改多例)
- 對象在Spring容器創建完成的時候就已經創建完成,不是需要用的時候才創建(Application創建時候對象就創建瞭)
- ApplicationContext就是IOC容器的接口,可以通過此對象獲取容器中創建的對象
2、通過bean的類型獲取對象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml"); Person bean = context.getBean(Person.class); System.out.println(bean);
註意:通過bean的類型在查找對象的時候,在配置文件中不能存在兩個類型一致的bean對象,如果有的話,可以通過如下方法
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml"); Person person = context.getBean("person", Person.class); System.out.println(person); } }
3、通過構造器給bean對象賦值
總結:
- constructor-arg 給person類添加構造方法
- 使用構造器賦值的時候可以省略name屬性,但是此時就要求必須嚴格按照構造器參數的順序來填寫瞭
- 如果想不按照順序來添加參數值,那麼可以搭配index屬性來使用
- 當有多個參數個數相同,不同類型的構造器的時候,可以通過type來強制類型
- 兩個重載的構造方法,後面的構造方法覆蓋前面的構造方法。
constructor-arg中五個屬性值: value:賦值 name:成員屬性 ref :通過ref引用其他對象,引用外部bean index:如果想不按照順序來添加參數值,那麼可以搭配index屬性來使用 type:當有多個參數個數相同,不同類型的構造器的時候,可以通過type來強制類型
ioc.xml
<!--給person類添加構造方法--> <bean id="person2" class="com.mashibing.bean.Person"> <constructor-arg name="id" value="1"></constructor-arg> <constructor-arg name="name" value="lisi"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> <constructor-arg name="gender" value="女"></constructor-arg> </bean> <!--在使用構造器賦值的時候可以省略name屬性,但是此時就要求必須嚴格按照構造器參數的順序來填寫瞭--> <bean id="person3" class="com.mashibing.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20"></constructor-arg> <constructor-arg value="女"></constructor-arg> </bean> <!--如果想不按照順序來添加參數值,那麼可以搭配index屬性來使用--> <bean id="person4" class="com.mashibing.bean.Person"> <constructor-arg value="lisi" index="1"></constructor-arg> <constructor-arg value="1" index="0"></constructor-arg> <constructor-arg value="女" index="3"></constructor-arg> <constructor-arg value="20" index="2"></constructor-arg> </bean> <!--當有多個參數個數相同,不同類型的構造器的時候,可以通過type來強制類型--> 將person的age類型設置為Integer類型 public Person(int id, String name, Integer age) { this.id = id; this.name = name; this.age = age; System.out.println("Age"); } // 後面的構造方法覆蓋前面的構造方法。 public Person(int id, String name, String gender) { this.id = id; this.name = name; this.gender = gender; System.out.println("gender"); } <bean id="person5" class="com.mashibing.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20" type="java.lang.Integer"></constructor-arg> </bean> <!--如果不修改為integer類型,那麼需要type跟index組合使用--> <bean id="person5" class="com.mashibing.bean.Person"> <constructor-arg value="1"></constructor-arg> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="20" type="int" index="2"></constructor-arg> </bean>
4、通過命名空間為bean賦值,簡化配置文件中屬性聲明的寫法
p導入命名空間,還有c命名空間,更簡單的命名方式,僅此而已。、
1、導入命名空間–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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
2、添加配置ioc.xml
<bean id="person6" class="com.mashibing.bean.Person" p:id="3" p:name="wangwu" p:age="22" p:gender="男"></bean>
5、為復雜類型進行賦值操作(重點)
總結:
給各種復雜類型賦值,如集合、數組、其他對象等。
創建類如下:Person.java 、 Book.java、 Address.java 作為演示
Person.java
import java.util.*; public class Person { private int id; private String name="dahuang"; private int age; private String gender; private Address address; private String[] hobbies; private List<Book> books; private Set<Integer> sets; private Map<String,Object> maps; private Properties properties; // 沒用過這個數據類型 public Person(int id, String name, int age, String gender) { this.id = id; this.name = name; this.age = age; this.gender = gender; System.out.println("有參構造器"); } public Person(int id, String name, int age) { this.id = id; this.name = name; this.age = age; System.out.println("Age"); } public Person(int id, String name, String gender) { this.id = id; this.name = name; this.gender = gender; System.out.println("gender"); } public Person() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public List<Book> getBooks() { return books; } public void setBooks(List<Book> books) { this.books = books; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } public String[] getHobbies() { return hobbies; } public void setHobbies(String[] hobbies) { this.hobbies = hobbies; } public Set<Integer> getSets() { return sets; } public void setSets(Set<Integer> sets) { this.sets = sets; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", address=" + address + ", hobbies=" + Arrays.toString(hobbies) + ", books=" + books + ", sets=" + sets + ", maps=" + maps + ", properties=" + properties + '}'; } }
Book.java
public class Book { private String name; private String author; private double price; public Book() { } public Book(String name, String author, double price) { this.name = name; this.author = author; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Book{" + "name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + '}'; } }
Address.java
public class Address { private String province; private String city; private String town; public Address() { } public Address(String province, String city, String town) { this.province = province; this.city = city; this.town = town; public String getProvince() { return province; public void setProvince(String province) { public String getCity() { return city; public void setCity(String city) { public String getTown() { return town; public void setTown(String town) { @Override public String toString() { return "Address{" + "province='" + province + '\'' + ", city='" + city + '\'' + ", town='" + town + '\'' + '}'; }
ioc.xml
給復雜類型的賦值都在property標簽內進行 1. 賦值為null <property name="name"> <null></null> </property> 2.外部引用 ref 3.引用內部bean 4.為list賦值 5.為set賦值 <property name="sets"> <set> <value>111</value> <value>222</value> <value>222</value> </set> </property> 6。為map賦值 <property name="maps" ref="myMap"></property> <util:map id="myMap"> <entry key="key1" value="value1"></entry> <entry key="key2" value-ref="book2"></entry> <entry key="key03"> <bean class="com.yao.bean.Book"> <property name="name" value="西遊記" ></property> <property name="author" value="吳承恩" ></property> <property name="price" value="100" ></property> </bean> </entry> </util:map> 7. 給數組賦值 <property name="hobbies"> <array> <value>book</value> <value>movie</value> <value>game</value> </array> </property>
ioc.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" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd" > <!--給復雜類型的賦值都在property標簽內進行--> <bean id="person" class="com.mashibing.bean.Person"> <property name="name"> <!--賦空值--> <null></null> </property> <!--通過ref引用其他對象,引用外部bean--> <property name="address" ref="address"></property> <!--引用內部bean--> <!-- <property name="address"> <bean class="com.mashibing.bean.Address"> <property name="province" value="北京"></property> <property name="city" value="北京"></property> <property name="town" value="西城區"></property> </bean> </property>--> <!--為list賦值--> <property name="books"> <list> <!--內部bean--> <bean id="book1" class="com.mashibing.bean.Book"> <property name="name" value="多線程與高並發"></property> <property name="author" value="馬士兵"></property> <property name="price" value="1000"></property> </bean> <!--外部bean--> <ref bean="book2"></ref> </list> </property> <!--給map賦值--> <property name="maps" ref="myMap"></property> <!--給property賦值--> <property name="properties"> <props> <prop key="aaa">aaa</prop> <prop key="bbb">222</prop> </props> </property> <!--給數組賦值--> <property name="hobbies"> <array> <value>book</value> <value>movie</value> <value>game</value> </array> </property> <!--給set賦值--> <property name="sets"> <set> <value>111</value> <value>222</value> <value>222</value> </set> </property> </bean> <bean id="address" class="com.mashibing.bean.Address"> <property name="province" value="河北"></property> <property name="city" value="邯鄲"></property> <property name="town" value="武安"></property> </bean> <bean id="book2" class="com.mashibing.bean.Book"> <property name="name" value="JVM"></property> <property name="author" value="馬士兵"></property> <property name="price" value="1200"></property> </bean> <!--級聯屬性--> <bean id="person2" class="com.mashibing.bean.Person"> <property name="address" ref="address"></property> <property name="address.province" value="北京"></property> </bean> <!--util名稱空間創建集合類型的bean--> <util:map id="myMap"> <entry key="key1" value="value1"></entry> <entry key="key2" value-ref="book2"></entry> <entry key="key03"> <bean class="com.mashibing.bean.Book"> <property name="name" value="西遊記" ></property> <property name="author" value="吳承恩" ></property> <property name="price" value="100" ></property> </bean> </entry> </util:map> </beans>
6、繼承關系bean的配置(暫時用不到)
意思就是bean可以繼承
parent:指定bean的配置信息繼承於哪個bean
parson2繼承parson 修改瞭name
abstract: 抽象bean,值在裡面,還是有就是不能實例化。abstract="true"
自己演示一下,好像沒啥用奧。
ioc.xml
<bean id="person" class="com.mashibing.bean.Person"> <property name="id" value="1"></property> <property name="name" value="zhangsan"></property> <property name="age" value="21"></property> <property name="gender" value="男"></property> </bean> <!--parent:指定bean的配置信息繼承於哪個bean--> <bean id="person2" class="com.mashibing.bean.Person" parent="person"> <property name="name" value="lisi"></property> </bean>
7、bean對象創建的依賴關系(暫時用不到)
bean對象在創建的時候是按照bean在配置文件的順序決定的,也可以使用depend-on標簽來決定順序
<bean id="book" class="com.mashibing.bean.Book" depends-on="person,address"></bean> <bean id="address" class="com.mashibing.bean.Address"></bean> <bean id="person" class="com.mashibing.bean.Person"></bean>
8、bean的作用域控制,是否是單例(一般兩種)
細節點區別:(面試的時候細節點)
prototype:容器啟動的時候不會創建多實例bean,隻有在獲取對象的時候才會創建該對象
singleton:在容器啟動完成之前就已經創建好對象
四種作用域 singleton 單例(默認的模式) prototype 多例模式 spring 4.x版本中: request: 每次發送請求都有一個新的對象 session:每次發送會話都有一個新的對象 這兩種方式幾乎不用。 測試singleton Person2 person2 = context.getBean("person2",Person.class); Person3 person3 = context.getBean("person3",Person.class); System.out.println(Person2== person3); // ture;
ioc.xml
<!-- bean的作用域:singleton、prototype、request、session 默認情況下是單例的 prototype:多實例的 容器啟動的時候不會創建多實例bean,隻有在獲取對象的時候才會創建該對象 每次創建都是一個新的對象 singleton:默認的單例對象 在容器啟動完成之前就已經創建好對象 獲取的所有對象都是同一個 --> <bean id="person4" class="com.mashibing.bean.Person" scope="prototype"></bean>
9、利用工廠模式創建bean對象
靜態工廠and實例工廠區別?
靜態工廠:工廠本身不需要創建對象,但是可以通過靜態方法調用,對象=工廠類.靜態工廠方法名();
實例工廠:工廠本身需要創建對象,工廠類 工廠對象=new 工廠類;工廠對象.get對象名();
優缺點:
實例工廠更容易擴展。
PersonStaticFactory.java
public class PersonStaticFactory { // 靜態工廠類 public static Person getPerson(String name){ Person person = new Person(); person.setId(1); person.setName(name); return person; } }
ioc.xml
<!-- 靜態工廠的使用: class:指定靜態工廠類 factory-method:指定哪個方法是工廠方法 --> <bean id="person5" class="com.mashibing.factory.PersonStaticFactory" factory-method="getPerson"> <!--constructor-arg:可以為方法指定參數--> <constructor-arg value="lisi"></constructor-arg> </bean>
Test.java
工廠創建:用這個 不用PersonStaticFactory類,因為用的工廠方法創建的。 Person2 person2 = context.getBean("person2",Person.class); System.out.println(Person2);
PersonInstanceFactory.java
public class PersonInstanceFactory { // 實例工廠類 不加static!! public Person getPerson(String name){ Person person = new Person(); person.setId(1); person.setName(name); return person; } }
ioc.xml
<!--實例工廠使用--> <!--創建實例工廠類--> <bean id="personInstanceFactory" class="com.mashibing.factory.PersonInstanceFactory"></bean> <!-- factory-bean:指定使用哪個工廠實例 factory-method:指定使用哪個工廠實例的方法 --> <bean id="person6" class="com.mashibing.bean.Person" factory-bean="personInstanceFactory" factory-method="getPerson"> <constructor-arg value="wangwu"></constructor-arg> </bean>
10、繼承FactoryBean來創建對象(一般用不到,源碼中看的多)
BeanFactory 接口,規范
FactoryBean:獲取唯一的對象。
自己創建的對象也可交給spring管理。
意思就是可以把我自己創建的交給Spring管理使用如下>
使用:
1)實現FactoryBean<那個類對象這裡是person>接口
2)三個方法:
工廠方法,返回需要創建的對象
返回對象的類型
否是單例對象
3)交給spring 配置ioc.xml下面有
總結:
創建對象的補充,用的時候才創建不用不會創建。跟單例多例沒有關系
自己不用。源碼會用的多。
11、bean對象的初始化和銷毀方法(瞭解)
初始化跟單例和多例有區別的:(一般沒人使用,面試知道)
如果bean是單例,容器在啟動的時候會創建好,關閉的時候會銷毀創建的bean
如果bean是多例,獲取的時候創建對象,銷毀的時候不會有任何的調用
12、配置bean對象初始化方法的前後處理方法(瞭解)
POSTxxxx接口
13、spring創建第三方bean對象(配置數據庫連接池)
1、導入數據庫連接池的pom文件
<!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
2、編寫配置文件
<?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"> <!-- Spring管理第三方Bean對象 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root"></property> <property name="password" value="123456"></property> <property name="url" value="jdbc:mysql://localhost:3306/demo"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> </bean> </beans>
3、編寫測試文件
public class MyTest { public static void main(String[] args) throws SQLException { ApplicationContext context = new ClassPathXmlApplicationContext("ioc3.xml"); DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class); System.out.println(dataSource); System.out.println(dataSource.getConnection()); } }
4、spring引用外部配置文件
5、spring基於xml文件的自動裝配
前面有address這個類,在ioc.xml中,就是用的propotery裝配。
現在自動裝配:
怎麼實現的?
byName:根據set方法後面首字幕大小寫裝配,必須首字幕小寫。
Type:按照類型裝配,有多個一樣的類型就報錯。
當一個對象中需要引用另外一個對象的時候,在之前的配置中我們都是通過property標簽來進行手動配置的,其實在spring中還提供瞭一個非常強大的功能就是自動裝配,可以按照我們指定的規則進行配置,配置的方式有以下幾種:
default/no:不自動裝配
byName:按照名字進行裝配,以屬性名作為id去容器中查找組件,進行賦值,如果找不到則裝配null
byType:按照類型進行裝配,以屬性的類型作為查找依據去容器中找到這個組件,如果有多個類型相同的bean對象,那麼會報異常,如果找不到則裝配null
constructor:按照構造器進行裝配,先按照有參構造器參數的類型進行裝配,沒有就直接裝配null;如果按照類型找到瞭多個,那麼就使用參數名作為id繼續匹配,找到就裝配,找不到就裝配null
6、SpEL的使用(就是簡單語法糖,寫bean方便)
略:隻有公司要求讓你用的時候你再去看,現在看瞭不用也沒啥用。
7、SpringIOC的註解應用
Spring中註解標識:
Spring中包含4個主要的組件添加註解: @Controller:控制器,推薦給controller層添加此註解(接受用戶請求 web用的到) @Service:業務邏輯,推薦給業務邏輯層添加此註解 @Repository:倉庫管理,推薦給數據訪問層添加此註解 @Component:給不屬於以上基層的**組件**添加此註解(啥也不懂就加這個)
註解使用步驟
使用註解需要如下步驟:
1、添加上述四個註解中的任意一個
2、添加自動掃描註解的組件,此操作需要依賴context命名空間
3、添加自動掃描的標簽context:component-scan(當前包下面的所有類都進行掃描)
問題:在使用註解的時候咱們沒有定義id和class他是怎麼識別的呢?
默認類的名字首字母,小寫,但是可以起別名,一般沒人這麼做,在註解標識括號中添加value = "xxxxxx",如@Controler(value = "類的名字就可以改");
掃描包可以做耕細粒度的劃分(沒啥用)
使用@AutoWired進行自動註入(理解困難,看看視頻)
面試題:
註意:當使用AutoWired註解的時候,自動裝配的時候是根據類型實現的。
1、如果隻找到一個,則直接進行賦值,
2、如果沒有找到,則直接拋出異常,
3、如果找到多個,那麼會按照變量名作為id繼續匹配,
1、匹配上直接進行裝配
2、如果匹配不上則直接報異常還可以使用@Qualifier註解來指定id的名稱,讓spring不要使用變量名,當使用@Qualifier註解的時候也會有兩種情況:
1、找到,則直接裝配
2、找不到,就會報錯
@AutoWired可以進行定義在方法上
自動裝配的註解@AutoWired,@Resource
面試題:
在使用自動裝配的時候,出瞭可以使用@AutoWired註解之外,還可以使用@Resource註解,大傢需要知道這**兩個註解的區別**。
1、@AutoWired:是spring中提供的註解,@Resource:是jdk中定義的註解,依靠的是java的標準
2、@AutoWired默認是按照類型進行裝配,默認情況下要求依賴的對象必須存在,@Resource默認是按照名字進行匹配的,同時可以指定name屬性。
3、@AutoWired隻適合spring框架,而@Resource擴展性更好
6、泛型依賴註入(先跳過把)
到此這篇關於Spring從入門到源碼—IOC基本使用(二)的文章就介紹到這瞭,更多相關Spring入門IOC內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 基於Spring depends-on的使用詳解
- Spring IOC創建對象的兩種方式
- Spring IOC容器Bean管理XML註入集合類型屬性
- Spring-IOC容器-Bean管理-基於XML方式超詳解
- Spring操作JdbcTemplate數據庫的方法學習