Spring是一個開源免費的框架,爲了解決企業應用開發的複雜性而建立。Spring框架是一個輕量級的解決方案,能夠一站式地構建企業級應用。Spring是模塊化的,因此能夠只使用其中須要的部分。能夠在任何web框架上使用控制反轉(IoC),也能夠只使用Hibernate集成代碼或JDBC抽象層。它支持聲明式事務管理、經過RMI或web服務實現遠程訪問,並可使用多種方式持久化數據。它提供了功能全面的MVC框架,能夠透明地集成AOP到軟件中。html
Spring被設計爲非侵入式的,這意味着你的域邏輯代碼一般不會依賴於框架自己。在集成層(好比數據訪問層),會存在一些依賴同時依賴於數據訪問技術和Spring,可是這些依賴能夠很容易地從代碼庫中分離出來。java
Spring框架是基於Java平臺的,它爲開發Java應用提供了全方位的基礎設施支持,而且它很好地處理了這些基礎設施,因此你只須要關注你的應用自己便可。mysql
Spring可使用POJO(普通的Java對象,plain old java objects)建立應用,而且能夠將企業服務非侵入式地應用到POJO。這項功能適用於Java SE編程模型以及所有或部分的Java EE。git
那麼,作爲開發者能夠從Spring得到哪些好處呢?github
不用關心事務API就能夠執行數據庫事務;web
不用關心遠程API就可使用遠程操做;正則表達式
不用關心JMX API就能夠進行管理操做;spring
不用關心JMS API就能夠進行消息處理。sql
①JMX,Java Management eXtension,Java管理擴展,是一個爲應用程序、設備、系統等植入管理功能的框架。JMX能夠跨越一系列異構操做系統平臺、系統體系結構和網絡傳輸協議,靈活的開發無縫集成的系統、網絡和服務管理應用。數據庫
②JMS,Java Message Service,Java消息服務,是Java平臺上有關面向消息中間件(MOM)的技術規範,它便於消息系統中的Java應用程序進行消息交換,而且經過提供標準的產生、發送、接收消息的接口簡化企業應用的開發。
一句話歸納:Spring是一個輕量級的控制反轉(IoC)和麪向切面(AOP)的容器(框架)。
官網: http://spring.io
文檔: https://docs.spring.io/spring/docs/current/spring-framework-reference/、 https://github.com/waylau/spring-framework-4-reference
中文幫助: http://spring.cndocs.ml/
框架下載地址: http://repo.springsource.org/libs-release-local/org/springframework/spring/
教程: http://www.yiibai.com/spring
Git: https://github.com/spring-projects
源碼: https://github.com/spring-projects/spring-framework
Jar包: https://github.com/spring-projects/spring-framework/releases
2002年,Rod Jahnson在《Expert One-on-One J2EE Design and Development》書中首次推出了Spring框架雛形interface21框架。
2004年3月24日,Spring框架以interface21框架爲基礎,通過從新設計,發佈了1.0正式版。
從2004年3月到如今,已經經歷了1.0、1.一、1.二、2.0、2.五、3.0、3.1幾個主要的版本
3.2.0版發佈 2013年5月5日13:53
3.2.10版發佈 2014年7月15日23:58
3.2.9版發佈 2014年5月20日12:22
4.0.0版發佈 2013年12月12日07:50
4.0.1版發佈 2014年1月28日20:55
4.1.6版發佈 2015年3月25日16:40
4.2.2版發佈 2015年10月15日12:57
4.2.5版發佈 2016年2月25日09:28
4.3.5版發佈 2016年12月21日11:34
4.3.6版發佈 2017年1月25日14:05
4.3.8版發佈 2017年4月18日13:49
4.3.9版發佈 2017年6月7日19:29
5.0.0版發佈 2017年9月28日11:28
5.0.1版發佈 2017年10月24日15:14
輕量:從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架能夠在一個大小隻有1MB多的JAR文件裏發佈。而且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的對象不依賴於Spring的特定類。
控制反轉Ioc:Spring經過一種稱做控制反轉(IoC)的技術促進了低耦合。當應用了IoC,一個對象依賴的其它對象會經過被動的方式傳遞進來,而不是這個對象本身建立或者查找依賴對象。你能夠認爲IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它。
面向切面Aop:Spring提供了面向切面編程的豐富支持,容許經過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用對象只實現它們應該作的——完成業務邏輯——僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支持。
容器:Spring包含並管理應用對象的配置和生命週期,在這個意義上它是一種容器,你能夠配置你的每一個bean如何被建立——基於一個可配置原型(prototype),你的bean能夠建立一個單獨的實例或者每次須要時都生成一個新的實例——以及它們是如何相互關聯的。然而,Spring不該該被混同於傳統的重量級的EJB容器,它們常常是龐大與笨重的,難以使用。
框架:Spring能夠將簡單的組件配置、組合成爲複雜的應用。在Spring中,應用對象被聲明式地組合,典型地是在一個XML文件裏。Spring也提供了不少基礎功能(事務管理、持久化框架集成等等),將應用邏輯的開發留給了你。
MVC:Spring的做用是整合,但不只僅限於整合,Spring 框架能夠被看作是一個企業解決方案級別的框架,Spring MVC是一個很是受歡迎的輕量級Web框架。
全部Spring的這些特徵使你可以編寫更乾淨、更可管理、而且更易於測試的代碼。它們也爲Spring中的各類模塊提供了基礎支持。
Spring 框架是一個分層架構,由 7 個定義良好的模塊組成。Spring 模塊構建在覈心容器之上,核心容器定義了建立、配置和管理 bean 的方式
組成 Spring 框架的每一個模塊(或組件)均可以單獨存在,或者與其餘一個或多個模塊聯合實現。每一個模塊的功能以下:
BeanFactory
,它是工廠模式的實現。BeanFactory
使用控制反轉(IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開。Spring 框架的功能能夠用在任何 J2EE 服務器中,大多數功能也適用於不受管理的環境。Spring 的核心要點是:支持不綁定到特定 J2EE 服務的可重用業務和數據訪問對象。毫無疑問,這樣的對象能夠在不一樣 J2EE 環境 (Web 或 EJB)、獨立應用程序、測試環境之間重用。
Spring是一個開源的框架,如今的Spring框架構成了一個體系平臺,經過Spring的官方網站http://www.springsource.org能夠了解到,圍繞着Spring框架自己,還有許多其餘優秀的項目:
SpringFramework(Core):核心項目
Spring Web Flow:工做流項目
Spring Security:安全項目
Spring Batch:批量數據處理項目
Spring Android:Android系統支持項目
Spring Social:社交項目
Spring Boot 是 Spring 的一套快速配置腳手架,能夠基於Spring Boot 快速開發單個微服務,Spring Cloud是一個基於Spring Boot實現的雲應用開發工具;Spring Boot專一於快速、方便集成的單個微服務個體,Spring Cloud關注全局的服務治理框架;Spring Boot使用了約束優於配置的理念,不少集成方案已經幫你選擇好了,能不配置就不配置,Spring Cloud很大的一部分是基於Spring Boot來實現,Spring Boot能夠離開Spring Cloud獨立使用開發項目,可是Spring Cloud離不開Spring Boot,屬於依賴的關係。
SpringBoot在SpringClound中起到了承上啓下的做用,若是你要學習SpringCloud必需要學習SpringBoot。
控制反轉IoC(Inversion of Control),是一種設計思想,DI(依賴注入)是實現IoC的一種方法,也有人認爲DI只是IoC的另外一種說法。沒有IoC的程序中咱們使用面向對象編程對象的建立與對象間的依賴關係徹底硬編碼在程序中,對象的建立由程序本身控制,控制反轉後將對象的建立轉移給第三方,我的認爲所謂控制反轉就是:得到依賴對象的方式反轉了。
IoC是Spring框架的核心內容,使用多種方式完美的實現了IoC,可使用XML配置,也可使用註解,新版本的Spring也能夠零配置實現IoC。Spring容器在初始化時先讀取配置文件,根據配置文件或元數據建立與組織對象存入容器中,程序使用時再從Ioc容器中取出須要的對象。
採用XML方式配置Bean的時候,Bean的定義信息是和實現分離的,而採用註解的方式能夠把二者合爲一體,Bean的定義信息直接以註解的形式定義在實現類中,從而達到了零配置的目的。
控制反轉是一種經過描述(XML或註解)並經過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。
假設項目中須要完成對圖書的數據訪問服務,咱們定義好了IBookDAO接口與BookDAO實現類
建立maven項目:
IBookDAO接口以下:
package com.zhangguo.Spring051.ioc01; /** * 圖書數據訪問接口 */ public interface IBookDAO { /** * 添加圖書 */ public String addBook(String bookname); }
BookDAO實現類以下:
package com.zhangguo.Spring051.ioc01; /** * 圖書數據訪問實現類 */ public class BookDAO implements IBookDAO { public String addBook(String bookname) { return "添加圖書"+bookname+"成功!"; } }
Maven項目的pom.xml以下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhangguo</groupId> <artifactId>Spring051</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Spring051</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>4.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.4</version> </dependency> </dependencies> </project>
業務類BookService以下:
package com.zhangguo.Spring051.ioc01; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 圖書業務類 */ public class BookService { IBookDAO bookDAO; public BookService() { //容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans01.xml"); //從容器中得到id爲bookdao的bean bookDAO=(IBookDAO)ctx.getBean("bookdao"); } public void storeBook(String bookname){ System.out.println("圖書上貨"); String result=bookDAO.addBook(bookname); System.out.println(result); } }
容器的配置文件IOCBeans01.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"> <bean id="bookdao" class="com.zhangguo.Spring051.ioc01.BookDAO"></bean> </beans>
測試類Test以下:
package com.zhangguo.Spring051.ioc01; public class Test { @org.junit.Test public void testStoreBook() { BookService bookservice=new BookService(); bookservice.storeBook("《Spring MVC權威指南 初版》"); } }
運行結果:
以下所示,則上下文會使用無參構造方法建立對象
<?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="tom" class="spring02.Student"></bean> </beans>
Person.java
package spring02; /**人*/ public abstract class Person { public String name; }
Student.java
package spring02; /**學生*/ public class Student extends Person { /**身高*/ public int height; /**有參構造方法*/ public Student(String name,int height){ this.name=name; this.height=height; } @Override public String toString() { return "Student{" + "height=" + height+",name="+name +'}'; } }
School.java
package spring02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class School { public static void main(String[] args) { //IoC容器 ApplicationContext ctx= new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml"); //從容器中獲取對象 Person tom=ctx.getBean("tom",Person.class); System.out.println(tom); } }
配置文件beans02.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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="tom" class="spring02.Student"> <constructor-arg name="name" value="張柏川"></constructor-arg> <constructor-arg name="height" value="195"></constructor-arg> </bean> </beans>
運行結果:
注意:若是在使用構造方法時不想經過參數名稱指定參數則能夠直接使用索引,如:
<bean id="rose" class="spring02.Student"> <constructor-arg index="0" value="張柏芝"></constructor-arg> <constructor-arg index="1" value="196"></constructor-arg> </bean>
Address地址類:
package spring02; /**地址*/ public class Address { /**國家*/ private String country; /**城市*/ private String city; public Address() { } public Address(String country, String city) { this.country = country; this.city = city; } @Override public String toString() { return "Address{" + "country='" + country + '\'' + ", city='" + city + '\'' + '}'; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
配置文件beans02.xml:
<bean name="zhuhai" class="spring02.Address"> <property name="country" value="中國"></property> <property name="city" value="珠海"></property> </bean>
測試代碼:
package spring02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class School { public static void main(String[] args) { //IoC容器 ApplicationContext ctx= new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml"); //從容器中獲取對象 Person tom=ctx.getBean("rose",Person.class); Address zhuhai=ctx.getBean("zhuhai",Address.class); System.out.println(zhuhai); } }
運行結果:
便捷方式:
<?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"> <bean id="mark" class="entities.Person" p:height="100" p:name="mark"> </bean> </beans>
你可使用id 或(和) name 屬性來指定bean的標識符
Person
package spring02; /**人*/ public abstract class Person { /**姓名*/ public String name; /**地址*/ public Address address; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
Student
package spring02; /**學生*/ public class Student extends Person { /**身高*/ public int height; /**有參構造方法*/ public Student(String name,int height){ this.name=name; this.height=height; } /**有參構造方法*/ public Student(String name,int height,Address address){ this.name=name; this.height=height; this.address=address; } @Override public String toString() { return "Student{" + "height=" + height+",name="+name +'}'+address; } }
配置文件
<?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 name="zhuhai" class="spring02.Address"> <property name="country" value="中國"></property> <property name="city" value="珠海"></property> </bean> <bean id="tom" class="spring02.Student"> <constructor-arg name="name" value="張柏川"></constructor-arg> <constructor-arg name="height" value="195"></constructor-arg> <constructor-arg name="address" ref="zhuhai"></constructor-arg> </bean> <bean id="rose" class="spring02.Student"> <constructor-arg index="0" value="張柏芝"></constructor-arg> <constructor-arg index="1" value="196"></constructor-arg> <constructor-arg index="2" ref="zhuhai"></constructor-arg> </bean> </beans>
測試代碼:
package spring02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class School { public static void main(String[] args) { //IoC容器 ApplicationContext ctx= new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml"); //從容器中獲取對象 Person tom=ctx.getBean("tom",Person.class); Person rose=ctx.getBean("rose",Person.class); //Address zhuhai=ctx.getBean("zhuhai",Address.class); System.out.println(tom); System.out.println(rose); } }
運行結果:
從容器中取回的對象默認是單例的:
Person roseA=ctx.getBean("rose",Person.class); Person roseB=ctx.getBean("rose",Person.class); //Address zhuhai=ctx.getBean("zhuhai",Address.class); System.out.println(tom); System.out.println(roseA==roseB);
運行結果:
使用scope屬性能夠指定做用域
<bean id="rose" class="spring02.Student" scope="prototype"> <constructor-arg index="0" value="張柏芝"></constructor-arg> <constructor-arg index="1" value="196"></constructor-arg> <constructor-arg index="2" ref="zhuhai"></constructor-arg> </bean>
測試代碼:
//從容器中獲取對象 Person tom=ctx.getBean("tom",Person.class); Person roseA=ctx.getBean("rose",Person.class); Person roseB=ctx.getBean("rose",Person.class); //Address zhuhai=ctx.getBean("zhuhai",Address.class); System.out.println(tom); System.out.println(roseA==roseB);
運行結果:
ApplicationContext
實現的默認行爲就是再啓動時將全部 singleton bean提早進行實例化。 一般這樣的提早實例化方式是好事,由於配置中或者運行環境的錯誤就會被馬上發現,不然可能要花幾個小時甚至幾天。若是你不想 這樣,你能夠將單例bean定義爲延遲加載防止它提早實例化。延遲初始化bean會告訴Ioc容器在第一次須要的時候才實例化而不是在容器啓動時就實例化。
在XML配置文件中,延遲初始化經過<bean/>
元素的lazy-init
屬性進行控制,好比:
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/> <bean name="not.lazy" class="com.foo.AnotherBean"/>
XML:
<bean id="mark" class="entities.Person" lazy-init="true" scope="prototype"> <property name="name" value="mark"></property> <property name="height" value="185"></property> </bean>
用例:
@Test public void testMethod3() throws Exception { //經過spring配置文件初始化一個容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg.xml"); Thread.sleep(2000); Person mark1=ctx.getBean("mark",Person.class); Thread.sleep(2000); Person mark2=ctx.getBean("mark",Person.class); System.out.println(mark1==mark2); }
結果:
配置文件:
<bean id="tom" class="spring02.Student" init-method="init" destroy-method="over"> <constructor-arg name="name" value="張柏川"></constructor-arg> <constructor-arg name="height" value="195"></constructor-arg> <constructor-arg name="address" ref="zhuhai"></constructor-arg> </bean>
Student類:
package spring02; import java.io.File; /**學生*/ public class Student extends Person { /**身高*/ public int height; /**有參構造方法*/ public Student(String name,int height){ this.name=name; this.height=height; } /**有參構造方法*/ public Student(String name,int height,Address address){ this.name=name; this.height=height; this.address=address; } @Override public String toString() { return "Student{" + "height=" + height+",name="+name +'}'+address; } public void init(){ System.out.println("對象被建立"); } public void over(){ System.out.println("對象被回收"); } }
運行結果:
實現 org.springframework.beans.factory.DisposableBean 接口,容許一個bean當容器須要其銷燬時得到一次回調。 DisposableBean 接口也只規定了一個方法:
void destroy() throws Exception;
建議不使用 DisposableBean 回調接口,由於會與Spring耦合。使用@PreDestroy 註解或者指定一個普通的方法,但能由bean定義支持。基於XML配置的元數據,使用 <bean/> 的 destroy-method 屬性。例如,下面的定義:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
示例
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
與下面效果相同:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
示例:
public class AnotherExampleBean implements DisposableBean { public void destroy() { // do some destruction work (like releasing pooled connections) } }
可是不與Spring耦合。
上一個示例是使用傳統的xml配置完成IOC的,若是內容比較多則配置需花費不少時間,經過註解能夠減輕工做量,但註解後修改要麻煩一些,偶合度會增長,應該根據須要選擇合適的方法。
package com.zhangguo.Spring051.ioc02; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; /** * 圖書數據訪問實現類 */ @Component("bookdaoObj") public class BookDAO implements IBookDAO { public String addBook(String bookname) { return "添加圖書"+bookname+"成功!"; } }
在類上增長了一個註解Component,在類的開頭使用了@Component註解,它能夠被Spring容器識別,啓動Spring後,會自動把它轉成容器管理的Bean。
除了@Component外,Spring提供了3個功能基本和@Component等效的註解,分別對應於用於對DAO,Service,和Controller進行註解。
1:@Repository 用於對DAO實現類進行註解。
2:@Service 用於對業務層註解,可是目前該功能與 @Component 相同。
3:@Constroller用於對控制層註解,可是目前該功能與 @Component 相同。
package com.zhangguo.Spring051.ioc02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; /** * 圖書業務類 */ @Component public class BookService { IBookDAO bookDAO; public void storeBook(String bookname){ //容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans02.xml"); //從容器中得到id爲bookdao的bean bookDAO=(IBookDAO)ctx.getBean("bookdaoObj"); System.out.println("圖書上貨"); String result=bookDAO.addBook(bookname); System.out.println(result); } }
將構造方法中的代碼直接寫在了storeBook方法中,避免循環加載的問題。
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="com.zhangguo.Spring051.ioc02"></context:component-scan> </beans>
粗體字是新增的xml命名空間與模式約束文件位置。增長了註解掃描的範圍,指定了一個包,能夠經過屬性設置更加精確的範圍如:
<context>標記經常使用屬性配置:
resource-pattern:對指定的基包下面的子包進行選取
<context>子標記:
include-filter:指定須要包含的包
exclude-filter:指定須要排除的包
<!-- 自動掃描com.zhangguo.anno.bo中的類進行掃描 -->
<context:component-scan base-package="com.zhangguo.anno" resource-pattern="bo/*.class" />
<context:component-scan base-package="com.zhangguo.anno" >
<context:include-filter type="aspectj「 expression="com.zhangguo.anno.dao.*.*"/>
<context:exclude-filter type=「aspectj」 expression=「com.zhangguo.anno.entity.*.*」/>
</context:component-scan>
include-filter表示須要包含的目標類型,exclude-filter表示須要排除的目標類型,type表示採的過濾類型,共有以下5種類型:
Filter Type | Examples Expression | Description |
annotation | org.example.SomeAnnotation | 註解了SomeAnnotation的類 |
assignable | org.example.SomeClass | 全部擴展或者實現SomeClass的類 |
aspectj | org.example..*Service+ | AspectJ語法表示org.example包下全部包含Service的類及其子類 |
regex | org\.example\.Default.* | Regelar Expression,正則表達式 |
custom | org.example.MyTypeFilter | 經過代碼過濾,實現org.springframework.core.type.TypeFilter接口 |
expression表示過濾的表達式。
<!-- 一、若是僅但願掃描特定的類而非基包下的全部類,可以使用resource-pattern屬性過濾特定的類 --> <context:component-scan base-package="com.zhangguo.Spring051" resource-pattern="ioc04/A*.class"> </context:component-scan>
只掃描com.zhangguo.Spring051.ioc04下全部名稱以A開始的類。
<!--二、掃描註解了org.springframework.stereotype.Repository的類 exclude-filter表示排除,include-filter表示包含,能夠有多個--> <context:component-scan base-package="com.zhangguo.Spring051.ioc04"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
<!--三、aspectj類型,掃描dao下全部的類,排除entity下全部的類--> <context:component-scan base-package="com.zhangguo.anno" > <context:include-filter type="aspectj" expression="com.zhangguo.anno.dao.*.*"/> <context:exclude-filter type="aspectj" expression="com.zhangguo.anno.entity.*.*"/> </context:component-scan>
測試類
package com.zhangguo.Spring051.ioc02; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { @org.junit.Test public void testStoreBook() { //容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans02.xml"); BookService bookservice=ctx.getBean(BookService.class); bookservice.storeBook("《Spring MVC權威指南 第二版》"); } }
運行結果:
IBookDao接口
package spring11; public interface IBookDao { void add(); }
BookDao實現類
package spring11; import org.springframework.stereotype.Component; @Component("bookdao") public class BookDao implements IBookDao { public void add() { System.out.println("新增圖書成功!"); } }
MSBookDao實現類
package spring11; import org.springframework.stereotype.Component; @Component("bookdao") public class MSBookDao implements IBookDao { public void add() { System.out.println("新增圖書到SQLServer成功!"); } }
BookService測試類:
package spring11; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BookService { public static void main(String[] args) { //容器 ApplicationContext ctx= new ClassPathXmlApplicationContext(new String[]{"bookbean11.xml"}); //從容器中得到對象 IBookDao dao=ctx.getBean("bookdao",IBookDao.class); dao.add(); } }
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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <bean name="tom" class="spring02.Student" p:name="tom" p:height="224"/> <!--指定要掃描的包,若是有多個能夠用逗號隔開--> <context:component-scan base-package="spring11"> <!--使用正則排除以B開頭的類--> <context:exclude-filter type="regex" expression="spring11\.B.*"></context:exclude-filter> </context:component-scan> </beans>
運行結果:
指定兩個bookdao是不正確的,重名了,可是由於在組件掃描中咱們排除了一個全部也能夠正確運行。
默認容器中的bean是單例的:
//從容器中得到對象 IBookDao dao1=ctx.getBean("bookdao",IBookDao.class); IBookDao dao2=ctx.getBean("bookdao",IBookDao.class); System.out.println(dao1==dao2);
結果:
修改爲原型
package spring11; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component("bookdao") @Scope("prototype") public class MSBookDao implements IBookDao { public void add() { System.out.println("新增圖書到SQLServer成功!"); } }
結果:
用來指定bean的做用域
singleton---單例 只建立一個對象。
prototype---原型 想建立多少個就建立多少了。
request---針對Web項目,不一樣的請求建立單獨的Bean對象,同一個請求共享一個Bean。
session---針對Web項目,不一樣的會話建立單獨的Bean對象,同一個會話共享一個Bean。
默認狀況下Spring IoC容器在初始化時將Bean建立好存放到容器中:
測試:
@Test public void testMethod6() throws Exception { //經過spring配置文件初始化一個容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg2.xml"); Thread.sleep(6000); IBookDao dao=ctx.getBean("mssql",IBookDao.class); dao.add("<<Java EE>>"); }
結果:
此處等待6秒...
增長註解修改爲延遲初始化bean
package dao; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Repository; @Repository("mssql") @Lazy public class SQLServerBookDao implements IBookDao { public SQLServerBookDao() { System.out.println("SQLServerBookDao構造方法被調用"); } /** * 添加圖書 * * @param name */ public void add(String name) { System.out.println("添加圖書到SQLServer數據庫成功:"+name); } }
再次測試結果:
而後
@PostConstruct 初始化方法的註解方式 等同與在XML中聲明init-method=init
package dao; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Repository; import javax.annotation.PostConstruct; @Repository("mssql") @Lazy public class SQLServerBookDao implements IBookDao { public SQLServerBookDao() { System.out.println("SQLServerBookDao構造方法被調用"); } /** * 添加圖書 * * @param name */ public void add(String name) { System.out.println("添加圖書到SQLServer數據庫成功:"+name); } //init-method callback @PostConstruct public void init(){ System.out.println("SQLServerBookDao初建立完成了"); } }
結果
@PreDestroy 銷燬方法的註解方式 等同於在XML中聲明destory-method=destory
package dao; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Repository; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Repository("mssql") @Lazy public class SQLServerBookDao implements IBookDao { public SQLServerBookDao() { System.out.println("SQLServerBookDao構造方法被調用"); } /** * 添加圖書 * * @param name */ public void add(String name) { System.out.println("添加圖書到SQLServer數據庫成功:"+name); } //init-method callback @PostConstruct public void init(){ System.out.println("SQLServerBookDao初建立完成了"); } //destory-method callback @PreDestroy public void destory(){ System.out.println("SQLServerBookDao準備銷燬了"); } }
若是使用Compont註解時不指定名稱,基於@Componet及其擴展(如@Servic和自定義等)標註和classpath-scan定義的Bean,註解有一個value屬性,若是提供了,那麼就此Bean的名字。若是不提供。就會使用Spring默認的命名機制,即簡單類名且第一個字母小寫
package spring11; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component() //未指定名稱 @Scope("prototype") public class MSBookDao implements IBookDao { public void add() { System.out.println("新增圖書到SQLServer成功!"); } }
測試:
package spring11; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BookService { public static void main(String[] args) { //容器 ApplicationContext ctx= new ClassPathXmlApplicationContext(new String[]{"bookbean11.xml"}); //從容器中得到對象 IBookDao dao1=ctx.getBean("MSBookDao",IBookDao.class); IBookDao dao2=ctx.getBean("MSBookDao",IBookDao.class); System.out.println(dao1==dao2); dao1.add(); } }
結果:
在基於XML的配置中bean標籤還有不少屬性,如scope、Lazy、init-method、depends-on、Qualifier等。
從容器中獲取實例時也能夠直接根據類型獲取
package spring12; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; @Component public class BookStore { @Autowired BookService service; public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean12.xml"); BookStore store =ctx.getBean(BookStore.class); store.service.addNewBook(); A a=ctx.getBean("a",A.class); System.out.println(a); } } @Component class A{ } @Component class B extends A{ }
結果:
默認名稱時須要將首字母小寫,Camel命名規範:
package dao; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; @Component public class MySqlBookDao implements IBookDao { /** * 添加圖書 * * @param name */ public void add(String name) { System.out.println("添加圖書到MySQL數據庫成功:"+name); } }
測試:
@Test public void testMethod5() throws Exception { //經過spring配置文件初始化一個容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg2.xml"); IBookDao bookDao=ctx.getBean("mySqlBookDao",IBookDao.class); bookDao.add("《Spring從入門到精通》"); }
結果:
從配置文件中咱們能夠看出咱們並無聲明bookdaoObj與BookService類型的對象,但仍是從容器中得到了實例併成功運行了,緣由是:在類的開頭使用了@Component註解,它能夠被Spring容器識別,啓動Spring後,會自動把它轉成容器管理的Bean。
從上一個示例中能夠看出有兩個位置都使用了ApplicationContext初始化容器後得到須要的Bean,能夠經過自動裝配簡化。
package com.zhangguo.Spring051.ioc03; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; /** * 圖書數據訪問實現類 */ @Repository public class BookDAO implements IBookDAO { public String addBook(String bookname) { return "添加圖書"+bookname+"成功!"; } }
把註解修改爲了Repository,比Component更貼切一些,非必要。
package com.zhangguo.Spring051.ioc03; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Service; /** * 圖書業務類 */ @Service public class BookService { @Autowired IBookDAO bookDAO; public void storeBook(String bookname){ System.out.println("圖書上貨"); String result=bookDAO.addBook(bookname); System.out.println(result); } }
將類BookService上的註解替換成了Service;在bookDao成員變量上增長了一個註解@Autowired,該註解的做用是:能夠對成員變量、方法和構造函數進行註解,來完成自動裝配的工做,通俗來講就是會根據類型從容器中自動查到到一個Bean給bookDAO字段。@Autowired是根據類型進行自動裝配的,若是須要按名稱進行裝配,則須要配合@Qualifier。另外可使用其它註解,@ Resource :等同於@Qualifier,@Inject:等同於@ Autowired。
@Service用於註解業務層組件(咱們一般定義的service層就用這個)
@Controller用於註解控制層組件(如struts中的action)
@Repository用於註解數據訪問組件,即DAO組件
@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行註解。
裝配註解主要有:@Autowired、@Qualifier、@Resource,它們的特色是:
一、@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入;
二、@Autowired默認是按照類型裝配注入的,若是想按照名稱來轉配注入,則須要結合@Qualifier一塊兒使用;
三、@Resource註解是又J2EE提供,而@Autowired是由spring提供,故減小系統對spring的依賴建議使用@Resource的方式;若是Maven項目是1.5的JRE則需換成更高版本的。
四、@Resource和@Autowired均可以書寫註解在字段或者該字段的setter方法之上
五、@Autowired 能夠對成員變量、方法以及構造函數進行註釋,而 @Qualifier 的註解對象是成員變量、方法入參、構造函數入參。
六、@Qualifier("XXX") 中的 XX是 Bean 的名稱,因此 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。
七、@Autowired 註釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個,經過屬性required能夠設置非必要。
八、@Resource裝配順序
8.1. 若是同時指定了name和type,則從Spring上下文中找到惟一匹配的bean進行裝配,找不到則拋出異常
8.2. 若是指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
8.3. 若是指定了type,則從上下文中找到類型匹配的惟一bean進行裝配,找不到或者找到多個,都會拋出異常
8.4. 若是既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;若是沒有匹配,則回退爲一個原始類型進行匹配,若是匹配則自動裝配;
package com.zhangguo.Spring051.ioc05; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Service; /** * 圖書業務類 */ @Service public class BookService { public IBookDAO getDaoofbook() { return daoofbook; } /* @Autowired @Qualifier("bookdao02") public void setDaoofbook(IBookDAO daoofbook) { this.daoofbook = daoofbook; }*/ @Resource(name="bookdao02") public void setDaoofbook(IBookDAO daoofbook) { this.daoofbook = daoofbook; } /* @Autowired @Qualifier("bookdao02") */ IBookDAO daoofbook; /* public BookService(@Qualifier("bookdao02") IBookDAO daoofbook) { this.daoofbook=daoofbook; }*/ public void storeBook(String bookname){ System.out.println("圖書上貨"); String result=daoofbook.addBook(bookname); System.out.println(result); } }
測試運行
package com.zhangguo.Spring051.ioc03; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { @org.junit.Test public void testStoreBook() { //容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans03.xml"); BookService bookservice=ctx.getBean(BookService.class); bookservice.storeBook("《Spring MVC權威指南 第三版》"); } }
運行結果:
IBookDao
package spring12; /**圖書數據訪問接口*/ public interface IBookDao { /**添加新書*/ void save(String name); }
BookDao
package spring12; import org.springframework.stereotype.Repository; /** * 完成圖書數據訪問 */ @Repository public class BookDao implements IBookDao { public void save(String name) { System.out.println("添加圖書" + name + "到數據庫成功!"); } }
BookService
package spring12; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BookService { @Autowired IBookDao bookDao; /**新增一本書*/ public void addNewBook(){ String bookname="《Spring MVC學習指南》"; bookDao.save(bookname); } }
配置bookbean12.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!--指定要掃描的包,若是有多個能夠用逗號隔開--> <context:component-scan base-package="spring12"> </context:component-scan> </beans>
BookStore
package spring12; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; @Component public class BookStore { @Autowired BookService service; public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean12.xml"); BookStore store =ctx.getBean(BookStore.class); store.service.addNewBook(); } }
測試結果:
@Qualifier("XXX") 中的 XX是 Bean 的名稱,因此 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。qualifier的意思是合格者,經過這個標示,代表了哪一個實現類纔是咱們所須要的
先看下面這個示例:
package spring13; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; @Service public class QualifierTest { @Autowired IBookDao dao; public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean13.xml"); QualifierTest obj = ctx.getBean(QualifierTest.class); System.out.println(obj.dao); } } interface IBookDao { } @Repository class BookDaoA implements IBookDao { } @Repository class BookDaoB implements IBookDao { }
運行結果:
這樣報錯的緣由是找到了多個Bean,Spring不知道選擇那一個。使用Qualifier指定名稱
package spring13; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; @Service public class QualifierTest { @Autowired @Qualifier("daoA") IBookDao dao; public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean13.xml"); QualifierTest obj = ctx.getBean(QualifierTest.class); System.out.println(obj.dao); } } interface IBookDao { } @Repository("daoA") class BookDaoA implements IBookDao { } @Repository("daoB") class BookDaoB implements IBookDao { }
結果:
@Resource裝配順序
若是同時指定了name和type,則從Spring上下文中找到惟一匹配的bean進行裝配,找不到則拋出異常
若是指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
若是指定了type,則從上下文中找到類型匹配的惟一bean進行裝配,找不到或者找到多個,都會拋出異常
若是既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;若是沒有匹配,則回退爲一個原始類型進行匹配,若是匹配則自動裝配;
package spring13; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class ResourceTest { @Resource(name = "carB") ICarDao dao; public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean13.xml"); ResourceTest obj = ctx.getBean(ResourceTest.class); System.out.println(obj.dao); } } interface ICarDao { } @Repository("carA") class CarDaoA implements ICarDao { } @Repository("carB") class CarDaoB implements ICarDao { } /* @Resource裝配順序 若是同時指定了name和type,則從Spring上下文中找到惟一匹配的bean進行裝配,找不到則拋出異常 若是指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常 若是指定了type,則從上下文中找到類型匹配的惟一bean進行裝配,找不到或者找到多個,都會拋出異常 若是既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;若是沒有匹配,則回退爲一個原始類型進行匹配,若是匹配則自動裝配; */
運行結果:
示例:
package spring13; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Scope; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class InjectTest { //注入給構造方法 @Autowired public InjectTest(IUserDao dao2) { this.dao2=dao2; } //注入給成員變量,字段 @Resource IUserDao dao1; IUserDao dao2; IUserDao dao3; IUserDao dao4; //注入給屬性 @Autowired public void setDao3(IUserDao dao3) { this.dao3 = dao3; } //注入給方法參數 @Autowired public void injectDao4(IUserDao dao4, IUserDao dao5) { this.dao4 = dao4; System.out.println(dao5); } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean13.xml"); InjectTest obj = ctx.getBean(InjectTest.class); System.out.println(obj.dao1); System.out.println(obj.dao2); System.out.println(obj.dao3); System.out.println(obj.dao4); } } interface IUserDao { } @Scope("prototype") @Repository class UserDao implements IUserDao { }
結果:
6.一、綜合示例
所謂的零配置就是再也不使用xml文件來初始化容器,使用一個類型來替代,
IBookDAO代碼以下:
package com.zhangguo.Spring051.ioc06; /** * 圖書數據訪問接口 */ public interface IBookDAO { /** * 添加圖書 */ public String addBook(String bookname); }
IBookDAO的實現類BookDAO代碼以下:
package com.zhangguo.Spring051.ioc06; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; /** * 圖書數據訪問實現類 */ @Repository public class BookDAO implements IBookDAO { public String addBook(String bookname) { return "添加圖書"+bookname+"成功!"; } }
在BookDAO類上註解了@Repository當初始化時該類將被容器管理會生成一個Bean,能夠經過構造方法測試。
業務層BookService代碼以下:
package com.zhangguo.Spring051.ioc06; import javax.annotation.Resource; import org.springframework.stereotype.Service; /** * 圖書業務類 */ @Service public class BookService { @Resource IBookDAO bookDAO; public void storeBook(String bookname){ System.out.println("圖書上貨"); String result=bookDAO.addBook(bookname); System.out.println(result); } }
類BookService將對容器管理由於註解了@Service,初始化時會生成一個單例的Bean,類型爲BookService。在字段bookDAO上註解了@Resource,用於自動裝配,Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入。
新增一個用於替代原xml配置文件的ApplicationCfg類,代碼以下:
package com.zhangguo.Spring051.ioc06; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * 容器的配置類 */ @Configuration @ComponentScan(basePackages="com.zhangguo.Spring051.ioc06") public class ApplicationCfg { @Bean public User getUser(){ return new User("成功"); } }
@Configuration至關於配置文件中的<beans/>,ComponentScan至關於配置文件中的context:component-scan,屬性也同樣設置
,@Bean至關於<bean/>,只能註解在方法和註解上,通常在方法上使用,源碼中描述:@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}),方法名至關於id。中間使用到了User,User類的代碼以下:
package com.zhangguo.Spring051.ioc06; import org.springframework.stereotype.Component; @Component("user1") public class User { public User() { System.out.println("建立User對象"); } public User(String msg) { System.out.println("建立User對象"+msg); } public void show(){ System.out.println("一個學生對象!"); } }
初始化容器的代碼與之前有一些不同,具體以下:
package com.zhangguo.Spring051.ioc06; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test { @org.junit.Test public void testStoreBook() { //容器,註解配置應用程序容器,Spring經過反射ApplicationCfg.class初始化容器 ApplicationContext ctx=new AnnotationConfigApplicationContext(ApplicationCfg.class); BookService bookservice=ctx.getBean(BookService.class); bookservice.storeBook("《Spring MVC權威指南 第四版》"); User user1=ctx.getBean("user1",User.class); user1.show(); User getUser=ctx.getBean("getUser",User.class); getUser.show(); } }
容器的初始化經過一個類型完成,Spring經過反射ApplicationCfg.class初始化容器,中間user1與getUser是否爲相同的Bean呢?
答案是否認的,由於在ApplicationCfg中聲明的方法getUser當相於在xml文件中定義了一個<bean id="getUser" class="..."/>,在User類上註解@Component("user1")至關於另外一個<bean id="user1" class="..."/>。
運行結果:
小結:使用零配置和註解雖然方便,不須要編寫麻煩的xml文件,但並不是爲了取代xml,應該根據實例須要選擇,或兩者結合使用,畢竟使用一個類做爲容器的配置信息是硬編碼的,很差在發佈後修改。
package spring14; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Repository; public class NoXMLIoC { public static void main(String[] args) { //基於類型的配置 ApplicationContext ctx=new AnnotationConfigApplicationContext(AppCfg.class); ICarDao dao1=ctx.getBean(ICarDao.class); dao1.add("Spring Pro"); } } interface ICarDao{ void add(String name); } @Repository class CarDao implements ICarDao{ public void add(String name) { System.out.println("添加"+name+"成功!"); } } @Configuration @ComponentScan(basePackages = "spring14") class AppCfg{ }
運行結果:
package spring14; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Repository; public class NoXMLIoC { public static void main(String[] args) { //基於類型的配置 ApplicationContext ctx=new AnnotationConfigApplicationContext(AppCfg.class); ICarDao dao2=ctx.getBean("mysqlDao",ICarDao.class); dao2.add("Spring Pro"); } } interface ICarDao{ void add(String name); } class CarDao implements ICarDao{ public void add(String name) { System.out.println("添加"+name+"成功!"); } } @Configuration @ComponentScan(basePackages = "spring14") class AppCfg{ @Bean ICarDao mysqlDao(){ //方法名就是bean的name return new CarDao(); } }
運行結果:
package spring14; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Repository; public class NoXMLIoC { public static void main(String[] args) { //基於類型的配置 ApplicationContext ctx=new AnnotationConfigApplicationContext(AppCfg.class); ICarDao dao1=ctx.getBean("oracleDao",ICarDao.class); dao1.add("Spring Pro Oracle"); ICarDao dao2=ctx.getBean("mysqlDao",ICarDao.class); dao2.add("Spring Pro MySQL"); System.out.println(dao1==dao2); } } interface ICarDao{ void add(String name); } @Repository("oracleDao") class CarDao implements ICarDao{ public void add(String name) { System.out.println("添加"+name+"成功!"); } } @Configuration @ComponentScan(basePackages = "spring14") class AppCfg{ @Bean ICarDao mysqlDao(){ //方法名就是bean的name return new CarDao(); } }
運行結果:
@value註解能夠實現爲對象賦值,能夠直接指定值也能夠從properties文件中獲取,這裏主要講解兩種方式:
一、在resource目錄下建立一個properties文件,如db.properties:
二、在Spring配置文件中導入資源文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd "> <context:component-scan base-package="com.zhangguo.spring03.demo.v32"></context:component-scan> <!--屬性點位,location用於指定資源位置,ignore-unresolvable忽視不能解析的內容--> <context:property-placeholder location="db.properties" ignore-unresolvable="true"></context:property-placeholder> </beans>
三、經過@Value引用資源文件中的內容
package com.zhangguo.spring03.demo.v32; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; @Component public class DbUtils { @Value("com.jdbc.driver.Oracle") private String driver; @Value("${URL}") private String location; @Value("${userName}") private String uid; @Value("${password}") private String pwd; @Override public String toString() { return "DbUtils{" + "driver='" + driver + '\'' + ", location='" + location + '\'' + ", uid='" + uid + '\'' + ", pwd='" + pwd + '\'' + '}'; } public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }
四、測試
package com.zhangguo.spring03.demo.v32; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client32 { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg32.xml"); UserDao dao=ctx.getBean(UserDao.class); System.out.println(dao.dbUtils); } }
五、結果
一、建立配置類
package com.zhangguo.spring03.demo.v33; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.PropertySource; @Configuration @ComponentScan("com.zhangguo.spring03.demo.v33") @PropertySource("db.properties") public class SpringCfg { }
使用@ImportResource可能會產生的異常(前言中不容許有內容):
"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2017.2.1\lib\idea_rt.jar=5997:C:\Program Files\JetBrains\IntelliJ IDEA 2017.2.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;C:\Users\Administrator\Desktop\mybatis-generator-gui-0.8.4\Spring02\target\classes;H:\InstallFiles\javaKit\mavenRes\junit\junit\4.12\junit-4.12.jar;H:\InstallFiles\javaKit\mavenRes\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;H:\InstallFiles\javaKit\mavenRes\cglib\cglib\3.2.4\cglib-3.2.4.jar;H:\InstallFiles\javaKit\mavenRes\org\ow2\asm\asm\5.1\asm-5.1.jar;H:\InstallFiles\javaKit\mavenRes\org\apache\ant\ant\1.9.6\ant-1.9.6.jar;H:\InstallFiles\javaKit\mavenRes\org\apache\ant\ant-launcher\1.9.6\ant-launcher-1.9.6.jar;H:\InstallFiles\javaKit\mavenRes\org\springframework\spring-context\4.3.0.RELEASE\spring-context-4.3.0.RELEASE.jar;H:\InstallFiles\javaKit\mavenRes\org\springframework\spring-aop\4.3.0.RELEASE\spring-aop-4.3.0.RELEASE.jar;H:\InstallFiles\javaKit\mavenRes\org\springframework\spring-beans\4.3.0.RELEASE\spring-beans-4.3.0.RELEASE.jar;H:\InstallFiles\javaKit\mavenRes\org\springframework\spring-core\4.3.0.RELEASE\spring-core-4.3.0.RELEASE.jar;H:\InstallFiles\javaKit\mavenRes\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;H:\InstallFiles\javaKit\mavenRes\org\springframework\spring-expression\4.3.0.RELEASE\spring-expression-4.3.0.RELEASE.jar;H:\InstallFiles\javaKit\mavenRes\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar" com.zhangguo.spring03.demo.v33.Client33 十月 22, 2018 11:30:15 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@685f4c2e: startup date [Mon Oct 22 11:30:15 CST 2018]; root of context hierarchy 十月 22, 2018 11:30:17 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [db.properties] 十月 22, 2018 11:30:17 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 1 in XML document from class path resource [db.properties] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 前言中不容許有內容。 Exception in thread "main" org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 1 in XML document from class path resource [db.properties] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 前言中不容許有內容。 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:399) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources(ConfigurationClassBeanDefinitionReader.java:346) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:142) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116) at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:333) at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:681) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:523) at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84) at com.zhangguo.spring03.demo.v33.Client33.main(Client33.java:9) Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 前言中不容許有內容。 at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203) at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177) at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400) at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327) at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1472) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:994) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243) at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339) at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:76) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:429) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391) ... 16 more Process finished with exit code 1
二、測試
package com.zhangguo.spring03.demo.v33; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client33 { public static void main(String[] args) { ApplicationContext ctx=new AnnotationConfigApplicationContext(SpringCfg.class); UserDao dao=ctx.getBean(UserDao.class); System.out.println(dao.dbUtils); } }
三、結果
假若有如下屬性文件dev.properties, 須要注入下面的tag
tag=123
經過PropertyPlaceholderConfigurer
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="dev.properties" /> </bean>
代碼
@Value("${tag}") private String tag;
經過PreferencesPlaceholderConfigurer
<bean id="appConfig" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="location" value="dev.properties" /> </bean>
代碼:
@Value("${tag}") private String tag;
經過PropertiesFactoryBean
<bean id="config" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="dev.properties" /> </bean>
代碼:
@Value("#{config['tag']}") private String tag;
經過util:properties
效果同PropertiesFactoryBean同樣
代碼:
@Value("#{config['tag']}") private String tag;
https://git.coding.net/zhangguo5/Spring.git
https://www.bilibili.com/video/av16071354/
第一次做業
1.一、請完成全部基於XML配置Ioc上課示例。
1.二、請學會使用幫助文檔
1.三、請定義一個Animal動物類(名稱name,重量weight),定義兩個Animal子類貓Cat(品種type)與狗Dog(顏色color)
1.四、以Animal、Cat、Dog爲基礎練習3.1-3.6的全部知識點
1.五、請寫一個微型的Ioc框架(MiniIoc),實現最基礎的控制反轉功能(選作)
第二次做業
2.一、請完成全部基於註解、自動裝配的Ioc上課示例。
2.二、請定義一個Animal動物類(名稱name,重量weight),定義兩個Animal子類貓Cat(品種type)與狗Dog(顏色color)
2.三、以Animal、Cat、Dog爲基礎練習基於註解與自動裝配全部知識點,這裏使用XML做爲配置文件
第三次做業
3.一、請完成全部基於零配置實現Ioc上課示例。
3.三、以Animal、Cat、Dog爲基礎練習基於註解、自動裝配與零配置的綜合示例,儘可能貫穿全部知識點,這裏不使用XML做爲配置文件
@Compent 要求Spring容器管理,被Spring掃描,應用於不肯定的功能(寬泛)
@Repository 應用於數據訪問層 DAO
@Service 應用於業務層
@Controller 應用於控制層
註解要被Spring容器管理的類 -> 配置文件指定要掃描的包 ->初始化容器,得到bean
@Autowired 自動裝配,字段(成員變量)、方法、屬性、構造, 不支持指定名稱,配合@Qualifier
@Resource 自動裝配,指定名稱,指定類型,不屬於Spring javax
@Qualifier 在自動裝配時指定對象的名稱,避免多個不惟一的實例
@Autowired()
@Qualifier("z")
X x;
@Resource(name="z")
X x;
X@Compent("y") Y:X@Compent("z") Z:X