這篇文章為大家?guī)碛嘘P(guān)Spring容器以及spring ioc原理的介紹。文章不僅介紹Spring容器以及spring ioc原理的知識點(diǎn),還介紹了Spring的配置和使用,希望大家通過這篇文章能有所收獲。
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序設(shè)計(jì)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了伊川免費(fèi)建站歡迎大家使用!
一:spring ioc的原理:
小A剛到公司老大安排了一個(gè)活,公司前不久剛開發(fā)了一個(gè)社交網(wǎng)站,運(yùn)行不太穩(wěn)定,經(jīng)常會出現(xiàn)莫名其妙的bug,需要在必要的地方加上日志,方便找到錯(cuò)誤,小A很快就開發(fā)好了日志記錄類,為了以后的擴(kuò)展性,還添加了一個(gè)接口:
public interfaceILogger {
voiddoLog();
}
public classConsolLoggerimplementsILogger {
@Override
public voiddoLog() {
System.out.println("打印日志到控制臺");
}
}
先在添加好友功能這里增加一個(gè)日志:
public classFriend {
private ILoggerlogger=new ConsoleLogger ();
public voidaddFriend(){
System.out.println("添加好友!");
logger.doLog();//添加日志
}
}
發(fā)現(xiàn)好多地方需要添加的,一個(gè)一個(gè)加上去,三天后終于全部加好了。
這天老大又找到了小A:小A啊,現(xiàn)在日志是在控制臺打印的,你看能不能保存在文件里面啊。小A皺了皺眉,先估算了一下工作量,需要先開發(fā)一個(gè)保存日志到文件的類,然后逐個(gè)修改,工作量有點(diǎn)大哦,而且都是重復(fù)性的工作,太沒挑戰(zhàn),萬一以后還需要再改那豈不是又要浪費(fèi)幾天美好時(shí)光,有沒有簡單點(diǎn)的辦法呢?
工廠模式,小A突然靈光一閃,對就是它了,先寫一個(gè)記錄日志到文件的類:
public classFileLoggerimplementsILogger{
public voiddoLog(){
System.out.println("記錄日志到文件");
}
}
再寫一個(gè)工廠類:
public class LoggerFactory {
public static ILogger createLogger(){
return new FileLogger();
}
}
現(xiàn)在可以通過工廠創(chuàng)建日志對象了:
public class Friend {
private FileLogger logger = LoggerFactory.createLogger();
public void addFriend(){
System.out.println("添加好友!");
logger.doLog();//添加日志
}
}
以后再有需求變動的時(shí)候只需要修改工廠類就可以了,完美,等等似乎還有一點(diǎn)瑕疵,如果能夠?qū)崿F(xiàn)連工廠類都不需要修改豈不是更完美,有點(diǎn)得寸進(jìn)尺了哦,人類的智慧是無限的看步驟:
1. 將日志的實(shí)現(xiàn)類的全限定名放到配置文件中
<bean id = “myLogger” class=”cn.xh.logger.FileLogger”>
2. 通過xml解析根據(jù)id從配置文件中讀出日志的實(shí)現(xiàn)類的全限定名
3. 通過反射動態(tài)創(chuàng)建日志實(shí)現(xiàn)類的對象
修改以后的工廠類偽代碼如下:
public class LoggerFactory {
public static ILogger createLogger(String id){
//解析xml根據(jù)id獲取要?jiǎng)?chuàng)建的日志類的全限定名
//使用反射動態(tài)創(chuàng)建日志實(shí)現(xiàn)類對象
//將該對象返回
return;
}
}
如果需要修改日志類,現(xiàn)在只需要修改xml配置文件就可以了,完美。
這就是spring ioc實(shí)現(xiàn)的基本原理,當(dāng)然身為一個(gè)偉大的產(chǎn)品,怎么可以如此簡單呢.
在Spring中有一個(gè)核心概念叫容器,顧名思意,容器是用來裝東西的,裝的什么東西呢?就是需要管理的對象,裝在哪里呢?一個(gè)HashMap中, 大致的可以理解為以對象名為鍵,以對象本身為值的一個(gè)HashMap,當(dāng)然遠(yuǎn)比這要復(fù)雜。
我們用容器來實(shí)例化對象,管理對象之間的依賴。
在spring中有兩個(gè)重要的接口:BeanFactory和ApplicationContext,所謂的容器就是實(shí)現(xiàn)了BeanFactory接口或者BeanFactory接口的類的實(shí)例,BeanFactory是最頂層最基本的接口,它描述了容器需要實(shí)現(xiàn)的最基本的功能,比如對象的注冊,獲取。
public interfaceBeanFactory {
StringFACTORY_BEAN_PREFIX="&";
/*
*四個(gè)不同形式的getBean方法,獲取實(shí)例
*/
Object getBean(String name)throwsBeansException;
<T>TgetBean(String name, Class<T> requiredType)throwsBeansException;
<T>TgetBean(Class<T> requiredType)throwsBeansException;
Object getBean(String name, Object... args)throwsBeansException;
//是否存在
booleancontainsBean(String name);
//是否為單實(shí)例
booleanisSingleton(String name)throwsNoSuchBeanDefinitionException;
//是否為多例
booleanisPrototype(String name)throwsNoSuchBeanDefinitionException;//
//名稱、類型是否匹配
booleanisTypeMatch(String name, Class<?> targetType)
throwsNoSuchBeanDefinitionException;
//獲取類型
Class<?> getType(String name)throwsNoSuchBeanDefinitionException;
//根據(jù)實(shí)例的名字獲取實(shí)例的別名
String[] getAliases(String name);
}
ApplicationContext依賴BeanFactory接口,它描述的內(nèi)容更加廣泛,例如資源的獲取等等。
當(dāng)然除了這兩個(gè)接口還有很多其它接口,這里不重點(diǎn)討論,附上一張圖以作了解。
通常我們使用的最多的容器是實(shí)現(xiàn)了ApplicationContext接口的類,ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
ClassPathXmlApplicationContext在類路徑下尋找配置文件來實(shí)例化容器,默認(rèn)是讀取 src 目錄下的配置文件
FileSystemXmlApplicationContext在文件系統(tǒng)路徑下尋找配置文件來實(shí)例化容器,默認(rèn)是讀取項(xiàng)目名下一級,與src同級的配置文件
這里的配置文件是xml文件,它描述了被管理的對象和對象之間的依賴(beans.xml)。
<beansxmlns="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">
<beanid="userDao"class="cn.xh.dao.UserDaoImpl"></bean>
</beans>
在這個(gè)配置文件中有一行配置:
<beanid="userDao"class="cn.xh.dao.UserDaoImpl"></bean>
表示使用spring容器管理的對象UserDaoImpl
加載配置文件創(chuàng)建容器:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
獲取容器中的對象
UserDaoImpl userDao = (UserDaoImpl) applicationContext.getBean("userDao");
我們來比較一下beanFactory和applicationContext:
1.BeanFactory接口定義了容器的最基本功能,它可以讀取類的配置文檔,管理類的加載,實(shí)例化,維護(hù)類之間的依賴關(guān)系。實(shí)現(xiàn)它的容器實(shí)例化時(shí)并不會初始化配置文件中定義的類,初始化動作發(fā)生在第一次調(diào)用時(shí)。 第一次調(diào)用創(chuàng)建好對象后就放入緩存中以后使用直接從緩存中獲取。
2. applicationContext接口除了提供容器的基本功能外還提供了很多的擴(kuò)展功能,實(shí)現(xiàn)它的容器實(shí)例化時(shí)就會將配置文件中定義的類初始化。
3.最常用的的容器是實(shí)現(xiàn)了applicationContext接口的容器ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
三.spring ioc的注入方式。
spring依賴注入(DI),是spring 控制反轉(zhuǎn)(IOC)的具體實(shí)現(xiàn),在一個(gè)類A中需要一個(gè)成員變量B,以前是直接給B賦值,現(xiàn)在通過Spring容器在需要的時(shí)候?qū)的值注入到A對象中,簡單的說,就是通過spring在適當(dāng)?shù)臅r(shí)候給A的成員變量B賦值。
Spring的注入有三種方式:構(gòu)造方法注入,setter方法注入,接口注入,使用最廣泛的是setter方法注入,接口注入的方式現(xiàn)在已經(jīng)很少用了。我們重點(diǎn)介紹前面兩種注入方式:
構(gòu)造方法注入:
就是使用類中的構(gòu)造函數(shù),給成員變量賦值,注意這里是使用spring框架來為我們賦值,上代碼,創(chuàng)建一個(gè)Person類,通過構(gòu)造方法為其成員變量賦值。
public classPerson {
private intpid;
privateStringpname;
private intage;
publicPerson(intpid, String pname,intage) {
this.pid= pid;
this.pname= pname;
this.age= age;
}
@Override
publicString toString() {
return"Person{"+
"pid="+pid+
", pname='"+pname+'\''+
", age="+age+
'}';
}
}
spring的配置:
<beanid="person"class="cn.xh.dao.Person">
<constructor-argname="pid"value="1"></constructor-arg>
<constructor-argname="pname"value="張三"></constructor-arg>
<constructor-argname="age"value="18"></constructor-arg>
</bean>
通過<constructor-argname="pid"value="1"></constructor-arg>給Person的成員變量賦值。
構(gòu)造方法注入有它的局限性,試想一下如果有20個(gè)成員變量,構(gòu)造方法的參數(shù)豈不是要20個(gè),很不優(yōu)雅,使用setter方法注入可以解決這個(gè)問題。
Setter方法注入:
在一個(gè)類中我們往往會通過get和set方法來對成員變量進(jìn)行賦值和取值的操作,可以通過set方法來給成員變量賦值。
public classPerson {
private intpid;
privateStringpname;
private intage;
public intgetPid() {
returnpid;
}
public voidsetPid(intpid) {
this.pid= pid;
}
publicString getPname() {
returnpname;
}
public voidsetPname(String pname) {
this.pname= pname;
}
public intgetAge() {
returnage;
}
public voidsetAge(intage) {
this.age= age;
}
@Override
publicString toString() {
return"Person{"+
"pid="+pid+
", pname='"+pname+'\''+
", age="+age+
'}';
}
}
spring的配置:
<beanid="person"class="cn.xh.dao.Person">
<propertyname="pid"value="1"></property>
<propertyname="pname"value="張三"></property>
<propertyname="age"value="18"></property>
</bean>
配置<propertyname="pid"value="1"></property>以后可以通過類提供的set方法將值賦給成員變量。
使用setter方法注入有一個(gè)需要特別注意的地方,假如我們給Person類加一個(gè)有參的構(gòu)造函數(shù):
public classPerson {
private intpid;
privateStringpname;
private intage;
publicPerson(intpid, String pname,intage) {
this.pid= pid;
this.pname= pname;
this.age= age;
}
}
程序運(yùn)行的時(shí)候會報(bào)錯(cuò),原因就是當(dāng)我們加上有參構(gòu)造函數(shù)以后就不會默認(rèn)生成無參構(gòu)造函數(shù),使用setter方法注入容器啟動的時(shí)候會調(diào)用無參構(gòu)造函數(shù)去實(shí)例化對象,所以我們需要手動加上無參構(gòu)造函數(shù)。
看完上述內(nèi)容,你們對Spring容器以及spring ioc原理有進(jìn)一步的了解嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀。
文章標(biāo)題:Spring容器以及springioc原理介紹
標(biāo)題來源:http://muchs.cn/article28/igedcp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、Google、服務(wù)器托管、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)