Spring的實(shí)現(xiàn)有兩種方式,一是配置,二是注解
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供瑞金網(wǎng)站建設(shè)、瑞金做網(wǎng)站、瑞金網(wǎng)站設(shè)計(jì)、瑞金網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、瑞金企業(yè)網(wǎng)站模板建站服務(wù),10年瑞金做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。目錄為什么會(huì)有IOC和DI?
因?yàn)橐鉀Q原有代碼開發(fā)的問題:
IOC:控制反轉(zhuǎn),什么控制反轉(zhuǎn)?創(chuàng)建對(duì)象的權(quán)利由程序反轉(zhuǎn)到程序外部,也就是有IOC容器來創(chuàng)建對(duì)象。
DI:依賴注入,其實(shí)就是綁定,綁定什么呢?綁定兩個(gè)有依賴關(guān)系的對(duì)象。
IOC和DI的目標(biāo)和最終效果
使用IOC的步驟
//1.導(dǎo)入spring的坐標(biāo)spring-context,對(duì)應(yīng)版本是5.2.10.RELEASE
//2.配置bean-->//bean標(biāo)簽標(biāo)示配置bean
//id屬性標(biāo)示給bean起名字
//class屬性表示給bean定義類型
//3.獲取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//4.獲取bean(根據(jù)bean配置id獲?。?// BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 強(qiáng)轉(zhuǎn)對(duì)象
// bookDao.save();
這樣一套下來,業(yè)務(wù)層中的代碼就可以不new對(duì)象了,改為
接上面的IOC,實(shí)現(xiàn)DI的步驟
//5.刪除業(yè)務(wù)層中使用new的方式創(chuàng)建的dao對(duì)象
//6.提供對(duì)應(yīng)的set方法
//7.配置server與dao的關(guān)系-->//property標(biāo)簽表示配置當(dāng)前bean的屬性
//name屬性表示配置哪一個(gè)具體的屬性
//ref屬性表示參照哪一個(gè)bean
這里的一個(gè)對(duì)應(yīng)關(guān)系很重要
對(duì)于bean的基礎(chǔ)配置,
IOC容器為我們創(chuàng)建對(duì)象默認(rèn)為單例的,若想創(chuàng)建個(gè)多例的,需要在配置文件配置bean的scope屬性
使用bean的scope
屬性可以控制bean的創(chuàng)建是否為單例:
singleton
默認(rèn)為單例prototype
為非單例
//spring報(bào)錯(cuò)信息處理,看最后一個(gè)報(bào)錯(cuò)信息,這個(gè)解決了報(bào)錯(cuò)也就差不多可以解決,看不懂再看倒數(shù)第二個(gè)以此類推。
IOC容器創(chuàng)造bean對(duì)象其實(shí)是調(diào)用了構(gòu)造方法,并且這個(gè)方法不論是公有的還是私有的都可以調(diào)得到,因?yàn)橛玫搅朔瓷洹?/p>bean的實(shí)例化
因此bean實(shí)例化的第一個(gè)方法就是使用構(gòu)造方法。
以前為了解耦,往往不自己new對(duì)象,而是交給工廠new,現(xiàn)在呢,靜態(tài)工廠可以移交給spring來創(chuàng)建對(duì)象,需要配置要?jiǎng)?chuàng)造的bean的工廠方法(factory-method):
因此bean實(shí)例化的第二個(gè)方法就是使用靜態(tài)工廠。
第三個(gè)方法:用FactoryBean創(chuàng)建對(duì)象,用UserDaoFactoryBean
實(shí)現(xiàn)spring框架的一個(gè)FactoryBean接口,這是一個(gè)泛型,需要指定對(duì)象,并重寫接口的方法,接著在配置文件中配置
訓(xùn)練中的不足1:關(guān)于是生命周期的核心問題
生命周期的控制主要由兩種方是,第一種就是自己寫初始化(init)操作和銷毀(destory)操作,然后在配置文件中bean標(biāo)簽中添加init-method="初始化方法名" destroy-method="銷毀方法名"
而運(yùn)行后發(fā)現(xiàn)銷毀方法中的內(nèi)容并不會(huì)執(zhí)行,why?
因此解決方法就是:
關(guān)閉容器的兩種方式:
至此就介紹完了,但是這些初始化和銷毀實(shí)現(xiàn)起來步驟比較多也比較亂,Spring提供了兩個(gè)接口來完成生命周期的控制,好處是可以不用再進(jìn)行配置init-method
和destroy-method
,操作:在業(yè)務(wù)類實(shí)現(xiàn)接口時(shí)添加兩個(gè)接口InitializingBean
,DisposableBean
并實(shí)現(xiàn)接口中的兩個(gè)方法afterPropertiesSet
和destroy
,例如:
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {private BookDao bookDao;
public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;
}
public void save() {System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {System.out.println("service init");
}
}
DI相關(guān)內(nèi)容依賴注入的兩類方式
setter引用類型注入,現(xiàn)在類中注入setter方法,然后在配置文件中使用property標(biāo)簽注入
例如:
其中ref的值是bean的id,name的值是引用類的對(duì)象名。
setter簡單類型注入,先在類中聲明對(duì)應(yīng)的簡單數(shù)據(jù)類型的屬性,并提供對(duì)應(yīng)的setter方法,然后在配置文件中使用property標(biāo)簽注入
例如:
其中name的值是聲明的數(shù)據(jù)類型的名稱,value是它的值。
對(duì)于setter注入方式的基本使用就已經(jīng)介紹完了,
構(gòu)造器引用數(shù)據(jù)類型,刪除setter方法,添加帶有參數(shù)的構(gòu)造方法,然后在配置文件中使用標(biāo)簽
,例如
其中name屬性對(duì)應(yīng)的值為構(gòu)造函數(shù)中方法形參的參數(shù)名,必須要保持一致。ref屬性指向的是spring的IOC容器中其他bean對(duì)象。
構(gòu)造器簡單數(shù)據(jù)類型,刪除setter方法,添加帶有參數(shù)的構(gòu)造方法,然后在配置文件中使用標(biāo)簽
,例如
其中name屬性同上,value是它的值。
其實(shí)這倆在配置文件幾乎沒有差別不過一個(gè)property標(biāo)簽,一個(gè)是constructor-arg標(biāo)簽
那這兩個(gè)如何選擇呢?自己開發(fā)的模板推薦使用setter方法注入。
setter注入
簡單數(shù)據(jù)類型
引用數(shù)據(jù)類型
構(gòu)造器注入
簡單數(shù)據(jù)類型
引用數(shù)據(jù)類型
依賴注入的方式選擇上
自動(dòng)注入一般采用類型注入(byType),比如bean1依賴bean2,所以我們要在bean1標(biāo)簽的autowire屬性中設(shè)置為byType,此時(shí)bean2甚至都不需要id,IOC就可以幫我們自動(dòng)注入,當(dāng)然自動(dòng)注入只能注入引用類型。
環(huán)境:
BookServiceImpl中要調(diào)用BookDao的方法,勢必要在BookServiceImpl中聲明一個(gè)BookDao的對(duì)象,并且若實(shí)現(xiàn)自動(dòng)注入,則BookServiceImpl中必須有BookDao的setter方法,再進(jìn)行配置
如:
注意事項(xiàng):按照類型在Spring的IOC容器中如果找到多個(gè)對(duì)象,會(huì)報(bào)NoUniqueBeanDefinitionException
數(shù)組、list、set、map、properties一共有五種
先聲明集合,然后設(shè)置集合的setter方法,接著在配置中用property標(biāo)記相應(yīng)的bean,如:
100 200 300
100 200 300 itcast itheima boxuegu boxuegu
說明:
、
、
、
、
標(biāo)簽
和
標(biāo)簽是可以混用
標(biāo)簽改成
標(biāo)簽,這種方式用的比較少對(duì)象有我們自己的IOC幫忙創(chuàng)建的,還有第三方提供的,如何管理這些第三方提供的bean呢?
以Spring的IOC容器來管理Druid連接池對(duì)象為例:
1.使用第三方的技術(shù),需要在pom.xml添加依賴
2.在配置文件中將【第三方的類】制作成一個(gè)bean,讓IOC容器進(jìn)行管理
3.數(shù)據(jù)庫連接需要基礎(chǔ)的四要素驅(qū)動(dòng)
、連接
、用戶名
和密碼
,【如何注入】到對(duì)應(yīng)的bean中(driver,url,username,password)
4.從IOC容器中獲取對(duì)應(yīng)的bean對(duì)象,將其打印到控制臺(tái)查看結(jié)果。
對(duì)于一個(gè)陌生的第三方的bean,我們就要探索了,在mvnresportry搜索,然后看他是否可以用構(gòu)造方法注入,如若不行則用setter方法注入,使用setter方法注入則在配置文件中用property和value標(biāo)簽配置就可。
黑馬舉兩個(gè)數(shù)據(jù)連接池的例子,druid和C3p0
加載properties文件然而把這些配置寫在applicationContext.xml文件中是不合適的,所以我們往往將這些配置寫在jdbc.properties中
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=1234
因此要先在applicationContext.xml中進(jìn)行配置。
修改五個(gè)地方:
在xml中讀取jdbc.properties,使用${key}
來讀取properties配置文件中的內(nèi)容并完成屬性注入
到此讀取配置文件就介紹完了,然后這里有一個(gè)小坑,
如果我在jdbc.properties中寫了username而不是jdbc.username,然后在applicationContext.xml中使用${username},則獲取到的是并不是我設(shè)定的值,而是系統(tǒng)變量的值,如:
運(yùn)行結(jié)果:
如何解決這個(gè)問題?在xml中設(shè)置system-properties-mode=“NEVER”
再次運(yùn)行:
還有一個(gè)注意事項(xiàng),在xml中加載properties文件時(shí),location="*properties"表示當(dāng)前類路徑下所有的配置文件,但不夠規(guī)范,應(yīng)寫為location="classpath:*properties"
,而有時(shí)候需要加載jar包中的配置文件,則使用location="classpath*:*properties"
核心容器,可以把它簡單的理解為ApplicationContext
第一種,就是利用類ClassPathXmlApplicationContext
創(chuàng)建
第二種,利用類FileSystemXmlApplicationContext
來創(chuàng)建,此方法需要在后面跟配置文件的絕對(duì)路徑,但是當(dāng)項(xiàng)目的位置發(fā)生變化后,代碼也需要跟著改,耦合度較高,不推薦使用。
//第一種
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//第二種
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
獲取Bean的三種方式 :BookDao bookDao = (BookDao) ctx.getBean("bookDao"); //這種方式存在的問題是每次獲取的時(shí)候都需要進(jìn)行類型轉(zhuǎn)換
BookDao bookDao0 = ctx.getBean("bookBao",BookDao.class); //這種方式可以解決類型強(qiáng)轉(zhuǎn)問題,但是參數(shù)又多加了一個(gè),相對(duì)來說沒有簡化多少。
BookDao bookDao1 = ctx.getBean(BookDao.class); //這種方式就類似我們之前所學(xué)習(xí)依賴注入中的按類型注入。必須要確保IOC容器中該類型對(duì)應(yīng)的bean對(duì)象只能有一個(gè)。
//此三種方法各有利弊,選擇合適的就行
從ApplicationContext一直向上找,可以找到BeanFactory,所以ApplicationContext最上級(jí)的父接口為 BeanFactory,故我們也可以用BeanFactory來創(chuàng)建IOC容器,但是他有一些東西不夠全面,所以逐漸才有了ApplicationContext
使用 BeanFactory創(chuàng)造IOC容器:
public class AppForBeanFactory {public static void main(String[] args) {Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}
ApplicationContext和BeanFactory的區(qū)別:
BeanFactory是延遲加載,只有在獲取bean對(duì)象的時(shí)候才會(huì)去創(chuàng)建
ApplicationContext是立即加載,容器加載的時(shí)候就會(huì)創(chuàng)建bean對(duì)象
ApplicationContext要想成為延遲加載,只需要在xml中的bean中添加lazy-init并將其設(shè)置為true,如:
核心容器總結(jié)這節(jié)中沒有新的知識(shí)點(diǎn),只是對(duì)前面知識(shí)的一個(gè)大總結(jié),共包含如下內(nèi)容:
容器相關(guān)其實(shí)整個(gè)配置中最常用的就兩個(gè)屬性id和class。
把scope、init-method、destroy-method框起來的原因是,后面注解在講解的時(shí)候還會(huì)用到,所以大家對(duì)這三個(gè)屬性關(guān)注下。
依賴注入相關(guān)IOC/DI注解開發(fā)注解開發(fā)定義bean
三步走:1.刪除配置文件中的bean、2.在要?jiǎng)?chuàng)建的bean的類上打注解@Component
,注意不要打在接口上,3.在配置中寫組件掃描component-scan
,并指定路徑.
小細(xì)節(jié),在@Component后面接(“id名稱”),然后在獲取bean是用id獲取再填后面接的名稱就可以一一對(duì)應(yīng)起來了例如
//BookServiceImpl.java
@Component("bookService.class")
public class BookServiceImpl implements BookService {public void save() {System.out.println("book service save ...");
}
//App.java
BookService bookService = (BookService) ctx.getBean("bookService.class");
;或者也可以用類型獲取的方式,在@Component后面什么寫不用寫,當(dāng)然如果不起名稱,會(huì)有一個(gè)默認(rèn)值就是當(dāng)前類名首字母小寫
,
@Component()
public class BookServiceImpl implements BookService {public void save() {System.out.println("book service save ...");
}
}
BookService bookService = (BookService) ctx.getBean(BookService.class);
純注解開發(fā)將配置文件改為一個(gè)Java文件然后在里面打入注解@Configration
就代替了配置文件,這種開發(fā)方式便叫:純注解開發(fā)
這個(gè)用來配置的java文件可以主包目錄下新建的config包中,也可以直接放在主包目錄下,spring均能檢測到
純注解開發(fā)步驟:
總結(jié)一下純注解就是把xml中的配置信息給他體現(xiàn)在Java文件中,怎么體現(xiàn)呢?
答:用注解的方式體現(xiàn),將某個(gè)配置在xml中的功能通過注解在類、屬性、方法等等的方式體現(xiàn)出來
用@PostConstruct和@PreDestroy注解方法,前者就是bean的初始化之前做的事,后者就是銷毀之后做的事
在這里呀要關(guān)閉容器,我們要調(diào)用close方法,但是報(bào)錯(cuò)了,我的記憶突然被喚起,ApplicationContext沒有close方法,之前學(xué)周期的之后說是ClassPathXmlApplicationContext有close方法,此時(shí)我們新建的對(duì)象是AnnotationConfigApplicationContext啊,所以等我一改成AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
報(bào)錯(cuò)取消了,開心~
小結(jié)一下
注解開發(fā)依賴注入純注解只有自動(dòng)裝配啊,沒有什么setter注入,也沒有構(gòu)造器注入,所以用@Autowired來注解,而@Autowired它是按照類型注入,如果我有兩個(gè)實(shí)現(xiàn)類實(shí)現(xiàn)了同一個(gè)接口,那么自動(dòng)注入就會(huì)報(bào)錯(cuò)啊,所以此時(shí)我們可以要用@Repository來表示不同的實(shí)現(xiàn)類,以此來達(dá)到用id來注入的目的
@Repository("bookDao")
public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ..." );
}
}
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {public void save() {System.out.println("book dao save ...2" );
}
}
但是這個(gè)方法不好,所以一般想用哪個(gè)就把@Qualifier注在哪個(gè)對(duì)象上
注:@Repository注解的作用就是對(duì)DAO中的類進(jìn)行注解,同時(shí)給每個(gè)類一個(gè)標(biāo)識(shí),也就是到時(shí)候?qū)OC中的bean一一對(duì)應(yīng)起來。
一般來說,dao中的類用@Repository來創(chuàng)建Bean,而service中的類用@Component來創(chuàng)建Bean
value注解既可以設(shè)置確定的值,也可以通過("${ }")
的方式將配置文件中的值賦值給成員變量,使用之前需要在java配置文件中寫入@PropertySource(“jdbc.properties”),括號(hào)內(nèi)為配置文件名,若是多文件則使用數(shù)組格式,如
@PropertySource({"jdbc.properties","jdbc1.properties","jdbc1.properties"})
用注解管理第三方bean主要是使用@Bean注解,在java配置文件中定義相應(yīng)的方法,并返回對(duì)象但凡整個(gè)第三方框架,都要使用@Bean
@Configuration
public class SpringConfig {//定義一個(gè)方法獲得要管理的對(duì)象
@Bean
public DataSource dataSource(){DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/db1");
ds.setUsername("root");
ds.setPassword("1234");
return ds;
}
}
但是你的jdbc配置寫在我SpringConfig中是個(gè)什么意思,到時(shí)候第三方的配置很多很多,都寫在一個(gè)文件顯然不方便,所以你自己在config包下創(chuàng)建自己的配置類,然后在其中寫方法,寫相應(yīng)的配置就ok,寫完之后得在總的配置類中匯報(bào)一下吧,那就用@Import注解注在SpringConfig上就ok
注解開發(fā)實(shí)現(xiàn)為第三方bean注入資源第三方的Bean我們可以管理了,但是如何為第三方注入資源呢?
注入的資源分為兩種,簡單類型與引用類型
簡單類型就@Value注解;引用類型就在方法中寫入你要注入的對(duì)象的形參
來一個(gè)需求(簡單類型):
1.resources目錄下添加jdbc.properties
2.配置文件中提供四個(gè)鍵值對(duì)分別是數(shù)據(jù)庫的四要素
3.使用@PropertySource加載jdbc.properties配置文件
4.修改@Value注解屬性的值,將其修改為${key}
,key就是鍵值對(duì)中的鍵的值
完成此需求最主要的就是,一要在SpringConfig中添加@PropertySource({"jdbc.properties"})
二在注解@Value中使用${}來獲取properties文件中的鍵名
那么引用類型呢?首先在第三方配置中掃描要注入的對(duì)象類型(用@ComponentScan),然后在第三方配置的方法中添加參數(shù),這個(gè)參數(shù)是引用類型的,如在第三方配置DruidDataSource中注入一個(gè)BookDao
@Bean
public DataSource dataSource(BookDao bookDao){System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
引用類型注入只需要為bean定義方法設(shè)置形參即可,容器會(huì)根據(jù)類型自動(dòng)裝配對(duì)象。
注解大總結(jié)+xml配置對(duì)比
標(biāo)紅的注解是最常用的,在開發(fā)中的使用頻率起碼要在百分之七十以上的~
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧