2.spring(二)
IOC理論推導 控制反轉
個人理解:當dao層有一個介面,很多實現類的時候,使用者的每一個請求進來,我們都需要手動的去修改程式碼,控制權在程式設計師手上,但當我們使用set方式的時候,請求就隨著使用者的需求變化,控制權就在使用者手上(底層:set原理)
- 之前,程式是主動的建立物件,控制權在程式手上
- 使用了set注入之後,程式設計師不在有主動權,而是被動的接收物件
private UserDao userDao = new UserDaoImpl();
private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; }
將主動的建立物件改為了被動的接收物件
這種思想,從本質上解決了問題,我們不再去管理物件的建立了,系統的耦合性大大降低,可以更加專注的在業務上實現
IOC本質 控制反轉
控制反轉(ioc)是一種設計思想,DI是實現IOC的一種方法,也有人認為DI是IOC的另外一種說法,沒有IOC的程式中,我們使用面向物件程式設計,物件的建立與物件的依賴關係完全硬編碼在程式中,物件的建立由程式自己控制,控制反轉後將物件的建立移交給第三方,個人認為所謂的控制反轉就是獲得物件的以來方式反轉了
上圖使用到的就是IOC容器
IOC是spring框架的核心內容,使用多種方法完美的實現了IOC,可以使用xml配置,也可以使用註解配置,新版本的spring可以實現零配置IOC
spring容器在被初始化的時候,先讀取配件(讀取bean),根據配置檔案或元素據建立組織物件存入容器中,程式使用時,再從IOC容器中取出需要的物件
採用xml配置bean的時候,bean的定義資訊和實現是分離的,而採用註解的方式,可以把兩者合為一體,bean的定義資訊直接以註解的形式定義在實現類中,從而達到零配置的目的
控制反轉是一種通過描述(xml或註解)並通過第三方去生產或獲取特定的物件方式,在spring中實現控制反轉的是IOC容器,其實現方式就是依賴注入DI
helloSpring
/** 實體類 */ public class Hello { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String toString() { return "Hello{" + "str='" + str + '\'' + '}'; } }
/**
ApplicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用spring建立物件,在spring中,這些都成為bean
Hellow hellow = new Hellow()
型別 變數名 = new 型別()
bean = 物件 new hellow
id 變數名
class new 的物件
property 相當於給物件的屬性設定一個值
-->
<!-- bean可以放多個,bean就是一個容器-->
<bean id="hellow" class="com.cdl.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
/**
myTest
*/
public class MyTest {
public static void main(String[] args) {
//獲取spring的上下文物件
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//我們的物件現在都在spring中管理了,我們要使用直接去取出來即可
Hello hellow = (Hello) context.getBean("hellow");
System.out.println(hellow.toString());
}
}
Hellow物件是誰建立的?
---- spring建立的
Hellow物件的屬性怎麼設定的?
spring容器設定的
這個過程就叫控制反轉
- 控制:誰來控制物件的建立,傳統應用的物件是有程式本身建立的,使用spring後,物件的建立由spring建立
- 反轉:程式本身不建立物件,而是被動的接收
- 依賴注入:利用set方法注入
- IOC就是一種思想,由主動程式設計程式設計了被動接收
IOC建立物件的方式
- 使用無參構造器(預設)
<bean id="stu2" class="com.bjsxt.spring2.Student"></bean>
- 使用有參構造器
- 下標賦值
- 型別
- 引數名
```<bean id="stu3" class="com.bjsxt.spring2.Student">
<!--<constructor-arg name="a" value="18"></constructor-arg>
<constructor-arg name="name" value="zs"></constructor-arg>
<constructor-arg name="sex" value="男"></constructor-arg>-->
<constructor-arg name="a" index="1" type="int" value="123"></constructor-arg>
<constructor-arg name="b" index="0" type="java.lang.String" value="456"></constructor-arg>
</bean>
總結:在配置檔案載入的時候,容器中管理的物件,就已經初始化了
spring配置說明
- alias 別名
<alias name="user" alias="userNew"/>
若添加了別名,也可以通過別名獲取物件
- import 引入
一般用於團隊開發使用,可以將多個配置檔案,匯入合併為一個
<import resources="bean.xml"/>
<import resources="beansNew.xml"/>
依賴注入 DI
三種方式
- 構造器注入(前面寫過了)
- set方式注入
實體類
/**
address類
*/
@Data
public class Address {
private String address;
}
/**
student類
*/
@Data
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,Object> card;
private Set<String> games;
private String wife;
private Properties properties;
}
配置檔案
/**
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.cdl.pojo.Address">
<property name="address" value="重慶"></property>
</bean>
<bean id="student" class="com.cdl.pojo.Student">
<!-- 第一種,直接注入-->
<property name="name" value="陳丹龍"></property>
<!-- 第二種,bean注入,使用ref
因為是一個類,現在上面使用bean注入address,然後是類,應該使用ref-->
<property name="address" ref="address"></property>
<!-- 第三種,陣列注入-->
<property name="books">
<array>
<value>三國演義</value>
<value>紅樓夢</value>
<value>水滸傳</value>
<value>西遊記</value>
</array>
</property>
<!-- list-->
<property name="hobbys">
<list>
<value>聽歌</value>
<value>看電影</value>
<value>寫程式碼</value>
</list>
</property>
<!-- map-->
<property name="card">
<map>
<entry key="身份證" value="420821199999999999"></entry>
<entry key="銀行卡" value="669826656366632565"></entry>
</map>
</property>
<!-- set-->
<property name="games">
<set>
<value>LOL</value>
<value>CF</value>
</set>
</property>
<!-- NULL-->
<property name="wife">
<null></null>
</property>
<!-- Properties配置檔案-->
<property name="properties">
<props>
<prop key="username">admin</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
/**
測試類
*/
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
/**
Student(
name=陳丹龍, address=Address(address=重慶),
books=[三國演義, 紅樓夢, 水滸傳, 西遊記],
hobbys=[聽歌, 看電影, 寫程式碼],
card={身份證=420821199999999999, 銀行卡=669826656366632565},
games=[LOL, CF],
wife=null,
properties={password=123456, username=admin})
*/
}
- 拓展方式 c名稱空間注入,P名稱空間注入
P名稱空間注入 屬性的注入
c名稱空間注入,構造器的注入
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
<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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p名稱空間,直接賦值屬性的值-->
<bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍"/>
<!-- c名稱空間,直接賦值屬性的值-->
<bean id="name" class="com.cdl.pojo.User" c:age="18" c:name="陳丹龍"/>
</beans>
public class MyTest02 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user = context.getBean("user",User.class);
System.out.println(user);
}
}
總結:P和C名稱空間不能直接使用,需要匯入xml約束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
Bean的作用域
- singleton 單例模式---預設級別---同一個物件呼叫多次,也只會建立一個
<bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍" scope="singleton"/>
- prototype 原型模式---每次從容器中get的時候,都會產生一個新的物件
<bean id="user" class="com.cdl.pojo.User" p:age="18" p:name="陳丹龍" scope="prototype"/>
- request,session,application,websocket這些都是在web開發中用到的
Bean的自動裝配
- 自動裝配是spring滿足Bean依賴的一種方式
- spring會在上下文中自動尋找,並自動給Bean裝配屬性(手動裝配:自己手動在配置檔案中給屬性設定預設值)
- 在spring中,有三種自動裝配的方式
- 在xml中顯示的配置
- 在java中顯示配置
- 隱試的自動裝配Bean【重要】
環境搭建(eg:一個人有兩隻寵物)
public class Cat {
public void show(){
System.out.println("miao~~~");
}
}
public class Dog {
public void show(){
System.out.println("wang~~~");
}
}
@Data
public class People {
private Cat cat;
private Dog dog;
private String name;
}
<?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="cat" class="com.cdl.pojo.Cat"></bean>
<bean id="dog" class="com.cdl.pojo.Dog"></bean>
<bean id="people" class="com.cdl.pojo.People">
<property name="name" value="陳丹龍"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
</beans>
public class Tset {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
People people = context.getBean("people",People.class);
people.getCat().show();
people.getDog().show();
}
}
ByName自動裝配
<?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="cat" class="com.cdl.pojo.Cat"></bean>
<bean id="dog" class="com.cdl.pojo.Dog"></bean>
<bean id="people" class="com.cdl.pojo.People" autowire="byName">
<property name="name" value="陳丹龍"></property>
</bean>
</beans>
ByName會自動在容器上下文查詢和自己物件set方法後面的值對應的BeanId
ByType自動裝配
<?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="cat12" class="com.cdl.pojo.Cat"></bean>
<bean id="dog12" class="com.cdl.pojo.Dog"></bean>
<bean id="people" class="com.cdl.pojo.People" autowire="byType">
<property name="name" value="陳丹龍"></property>
</bean>
</beans>
總結:ByName的時候,需要保證所有的bean的ID唯一,並且這個bean需要和自動注入的屬性的set方法的值一致
ByType的時候,需要保證所有的bean的class唯一,並且這個時候的bena需要和自動注入的屬性保持一致