您好,登錄后才能下訂單哦!
這篇文章為大家帶來有關Spring容器以及spring ioc原理的介紹。文章不僅介紹Spring容器以及spring ioc原理的知識點,還介紹了Spring的配置和使用,希望大家通過這篇文章能有所收獲。
一:spring ioc的原理:
小A剛到公司老大安排了一個活,公司前不久剛開發了一個社交網站,運行不太穩定,經常會出現莫名其妙的bug,需要在必要的地方加上日志,方便找到錯誤,小A很快就開發好了日志記錄類,為了以后的擴展性,還添加了一個接口:
public interface ILogger {
void doLog();
}
public class ConsolLogger implements ILogger {
@Override
public void doLog() {
System.out.println("打印日志到控制臺");
}
}
先在添加好友功能這里增加一個日志:
public class Friend {
private ILogger logger = new ConsoleLogger ();
public void addFriend(){
System.out.println("添加好友!");
logger.doLog();//添加日志
}
}
發現好多地方需要添加的,一個一個加上去,三天后終于全部加好了。
這天老大又找到了小A:小A啊,現在日志是在控制臺打印的,你看能不能保存在文件里面啊。小A皺了皺眉,先估算了一下工作量,需要先開發一個保存日志到文件的類,然后逐個修改,工作量有點大哦,而且都是重復性的工作,太沒挑戰,萬一以后還需要再改那豈不是又要浪費幾天美好時光,有沒有簡單點的辦法呢?
工廠模式,小A突然靈光一閃,對就是它了,先寫一個記錄日志到文件的類:
public class FileLogger implements ILogger{
public void doLog(){
System.out.println("記錄日志到文件");
}
}
再寫一個工廠類:
public class LoggerFactory {
public static ILogger createLogger(){
return new FileLogger();
}
}
現在可以通過工廠創建日志對象了:
public class Friend {
private FileLogger logger = LoggerFactory.createLogger();
public void addFriend(){
System.out.println("添加好友!");
logger.doLog();//添加日志
}
}
以后再有需求變動的時候只需要修改工廠類就可以了,完美,等等似乎還有一點瑕疵,如果能夠實現連工廠類都不需要修改豈不是更完美,有點得寸進尺了哦,人類的智慧是無限的看步驟:
1. 將日志的實現類的全限定名放到配置文件中
<bean id = “myLogger” class=”cn.xh.logger.FileLogger”>
2. 通過xml解析根據id從配置文件中讀出日志的實現類的全限定名
3. 通過反射動態創建日志實現類的對象
修改以后的工廠類偽代碼如下:
public class LoggerFactory {
public static ILogger createLogger(String id){
//解析xml根據id獲取要創建的日志類的全限定名
//使用反射動態創建日志實現類對象
//將該對象返回
return;
}
}
如果需要修改日志類,現在只需要修改xml配置文件就可以了,完美。
這就是spring ioc實現的基本原理,當然身為一個偉大的產品,怎么可以如此簡單呢.
在Spring中有一個核心概念叫容器,顧名思意,容器是用來裝東西的,裝的什么東西呢?就是需要管理的對象,裝在哪里呢?一個HashMap中, 大致的可以理解為以對象名為鍵,以對象本身為值的一個HashMap,當然遠比這要復雜。
我們用容器來實例化對象,管理對象之間的依賴。
在spring中有兩個重要的接口:BeanFactory和ApplicationContext,所謂的容器就是實現了BeanFactory接口或者BeanFactory接口的類的實例,BeanFactory是最頂層最基本的接口,它描述了容器需要實現的最基本的功能,比如對象的注冊,獲取。
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
/*
* 四個不同形式的getBean方法,獲取實例
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
// 是否存在
boolean containsBean(String name);
// 是否為單實例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//是否為多例
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;//
// 名稱、類型是否匹配
boolean isTypeMatch(String name, Class<?> targetType)
throws NoSuchBeanDefinitionException;
// 獲取類型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 根據實例的名字獲取實例的別名
String[] getAliases(String name);
}
ApplicationContext依賴BeanFactory接口,它描述的內容更加廣泛,例如資源的獲取等等。
當然除了這兩個接口還有很多其它接口,這里不重點討論,附上一張圖以作了解。
通常我們使用的最多的容器是實現了ApplicationContext接口的類,ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
ClassPathXmlApplicationContext在類路徑下尋找配置文件來實例化容器,默認是讀取 src 目錄下的配置文件
FileSystemXmlApplicationContext在文件系統路徑下尋找配置文件來實例化容器,默認是讀取項目名下一級,與src同級的配置文件
這里的配置文件是xml文件,它描述了被管理的對象和對象之間的依賴(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 id="userDao" class="cn.xh.dao.UserDaoImpl"></bean>
</beans>
在這個配置文件中有一行配置:
<bean id="userDao" class="cn.xh.dao.UserDaoImpl"></bean>
表示使用spring容器管理的對象UserDaoImpl
加載配置文件創建容器:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
獲取容器中的對象
UserDaoImpl userDao = (UserDaoImpl) applicationContext.getBean("userDao");
我們來比較一下beanFactory和applicationContext:
1.BeanFactory接口定義了容器的最基本功能,它可以讀取類的配置文檔,管理類的加載,實例化,維護類之間的依賴關系。實現它的容器實例化時并不會初始化配置文件中定義的類,初始化動作發生在第一次調用時。 第一次調用創建好對象后就放入緩存中以后使用直接從緩存中獲取。
2. applicationContext接口除了提供容器的基本功能外還提供了很多的擴展功能,實現它的容器實例化時就會將配置文件中定義的類初始化。
3.最常用的的容器是實現了applicationContext接口的容器ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
三.spring ioc的注入方式。
spring依賴注入(DI),是spring 控制反轉(IOC)的具體實現,在一個類A中需要一個成員變量B,以前是直接給B賦值,現在通過Spring容器在需要的時候將B的值注入到A對象中,簡單的說,就是通過spring在適當的時候給A的成員變量B賦值。
Spring的注入有三種方式:構造方法注入,setter方法注入,接口注入,使用最廣泛的是setter方法注入,接口注入的方式現在已經很少用了。我們重點介紹前面兩種注入方式:
構造方法注入:
就是使用類中的構造函數,給成員變量賦值,注意這里是使用spring框架來為我們賦值,上代碼,創建一個Person類,通過構造方法為其成員變量賦值。
public class Person {
private int pid;
private String pname;
private int age;
public Person(int pid, String pname, int age) {
this.pid = pid;
this.pname = pname;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", age=" + age +
'}';
}
}
spring的配置:
<bean id="person" class="cn.xh.dao.Person">
<constructor-arg name="pid" value="1"></constructor-arg>
<constructor-arg name="pname" value="張三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
通過<constructor-arg name="pid" value="1"></constructor-arg>給Person的成員變量賦值。
構造方法注入有它的局限性,試想一下如果有20個成員變量,構造方法的參數豈不是要20個,很不優雅,使用setter方法注入可以解決這個問題。
Setter方法注入:
在一個類中我們往往會通過get和set方法來對成員變量進行賦值和取值的操作,可以通過set方法來給成員變量賦值。
public class Person {
private int pid;
private String pname;
private int age;
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", age=" + age +
'}';
}
}
spring的配置:
<bean id="person" class="cn.xh.dao.Person">
<property name="pid" value="1"></property>
<property name="pname" value="張三"></property>
<property name="age" value="18"></property>
</bean>
配置<property name="pid" value="1"></property>以后可以通過類提供的set方法將值賦給成員變量。
使用setter方法注入有一個需要特別注意的地方,假如我們給Person類加一個有參的構造函數:
public class Person {
private int pid;
private String pname;
private int age;
public Person(int pid, String pname, int age) {
this.pid = pid;
this.pname = pname;
this.age = age;
}
}
程序運行的時候會報錯,原因就是當我們加上有參構造函數以后就不會默認生成無參構造函數,使用setter方法注入容器啟動的時候會調用無參構造函數去實例化對象,所以我們需要手動加上無參構造函數。
看完上述內容,你們對Spring容器以及spring ioc原理有進一步的了解嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。