文章大綱
一、Spring介紹
二、Spring的IoC實戰
三、IoC常見注解總結
四、項目源碼及參考資料下載
五、參考文章
一、Spring介紹
1. 什么是Spring
Spring是分層的Java SE/EE應用 full-stack輕量級開源框架,以IoC(Inverse Of Control:反轉控制)和AOP(Aspect Oriented Programming:面向切面編程)為內核,提供了展現層Spring MVC和持久層Spring JDBC以及業務層事務管理等眾多的企業級應用技術,還能整合開源世界眾多著名的第三方框架和類庫,逐漸成為使用最多的Java EE企業應用開源框架。
2. Spring優勢
方便解耦,簡化開發
通過Spring提供的IoC容器,可以將對象間的依賴關系交由Spring進行控制,避免硬編碼所造成的過度程序耦合。用戶也不必再為單例模式類、屬性文件解析等這些很底層的需求編寫代碼,可以更專注於上層的應用。
AOP編程的支持
通過Spring的AOP功能,方便進行面向切面的編程,許多不容易用傳統OOP(面向對象的程序設計)實現的功能可以通過AOP輕松應付。
聲明式事務的支持
可以將我們從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活的進行事務的管理,提高開發效率和質量。
方便程序的測試
可以用非容器依賴的編程方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是隨手可做的事情。
方便集成各種優秀框架
Spring可以降低各種框架的使用難度,提供了對各種優秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
降低JavaEE API的使用難度
Spring對JavaEE API(如JDBC、JavaMail、遠程調用等)進行了薄薄的封裝層,使這些API的使用難度大為降低。
3. spring的體系結構

二、Spring的IOC實戰
控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。
IoC有兩種實現方式,一種是配置文件(bean管理)方式,具體包括使用類的無參數構造方法(重點)、使用靜態工廠創建、使用實例工廠創建。第二種是注解方式。
1. 創建項目

2. 添加jar包(實際開發中使用maven)
將jar包復制到以下文件夾中

設置依賴
具體方式可參考博客中地址:https://zyjustin9.iteye.com/blog/2172445
3. 配置文件(bean管理)方式實現
方式一:使用id配置方法--常用(重要)
創建測試類User.java
public class User { public void add() { System.out.println("add......."); } public void add(String haha) { System.out.println("add.."+haha); } }
src下創建配置文件myXml.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" > <!-- 本來在該配置文件中還有一個屬性name,其作用和id一樣,id屬性值不能包含特殊符號(比如@#),但是name屬性可以,不過name屬性是很早版本時候使用的,現在都被替換成id了 scope屬性,總共有以下的值,但是最主要用的是前兩個,后面兩個不用記得,在該配置文件中我們沒有寫scope屬性,默認使用的是singleton singleton:默認值、單例的 prototype:多例的: request:創建對象,把對象放在request域里面 session:創建對象,把對象放在session域里面 globalSession:創建對象,把對象放在globalSession域里面 --> <!-- 第一種方法:ioc的配置文件 id是類的標志 class是對象類全路徑--> <bean id="user" class="ioc1.User" scope="singleton"/> </beans>
編寫測試代碼
/** * 測試配置方式實現IOC三種方法 * * @author 吳曉暢 * */ public class TestIoc { @Test public void testUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("myXml.xml"); //方法1 :使用id配置方法--常用 User user = (User) context.getBean("user"); System.out.println(user); user.add("尼瑪"); } }
運行結果如下:

方式二:靜態工廠(了解就好)
創建測試類User2.java
package ioc2; public class User2 { public void add() { System.out.println("user2........"); } }
創建測試工廠類User2Factory.java
package ioc2; public class User2Factory { public static User2 getUser2() { return new User2(); } }
src下創建配置文件myXml.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" > <!-- 本來在該配置文件中還有一個屬性name,其作用和id一樣,id屬性值不能包含特殊符號(比如@#),但是name屬性可以,不過name屬性是很早版本時候使用的,現在都被替換成id了 scope屬性,總共有以下的值,但是最主要用的是前兩個,后面兩個不用記得,在該配置文件中我們沒有寫scope屬性,默認使用的是singleton singleton:默認值、單例的 prototype:多例的: request:創建對象,把對象放在request域里面 session:創建對象,把對象放在session域里面 globalSession:創建對象,把對象放在globalSession域里面 --> <!-- 第二種方法:使用靜態工廠創建對象 --> <bean id="user2" class="ioc2.User2Factory" factory-method="getUser2"/> </beans>
測試代碼如下:
package introduction; import ioc1.User; import ioc2.User2; import ioc3.User3; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 測試配置方式實現IOC三種方法 * * @author 吳曉暢 * */ public class TestIoc { @Test public void testUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("myXml.xml"); //方法2:使用靜態工廠方法--了解就好 User2 user2 = (User2) context.getBean("user2"); System.out.println(user2); } }
運行結果如下:

方式三:實例工廠(了解就好)
創建測試類User3.java
package ioc3; public class User3 { public void add() { System.out.println("user3........"); } }
創建測試工廠類User3Factory.java
package ioc3; public class User3Factory { //普通方法,返回User3對象 public User3 getUser3() { return new User3(); } }
src下創建配置文件myXml.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" > <!-- 本來在該配置文件中還有一個屬性name,其作用和id一樣,id屬性值不能包含特殊符號(比如@#),但是name屬性可以,不過name屬性是很早版本時候使用的,現在都被替換成id了 scope屬性,總共有以下的值,但是最主要用的是前兩個,后面兩個不用記得,在該配置文件中我們沒有寫scope屬性,默認使用的是singleton singleton:默認值、單例的 prototype:多例的: request:創建對象,把對象放在request域里面 session:創建對象,把對象放在session域里面 globalSession:創建對象,把對象放在globalSession域里面 --> <!-- 第三種方法:使用實例工廠創建對象 --> <!-- 創建工廠類的對象 --> <bean id="User3Factory" class="ioc3.User3Factory"></bean> <bean id="user3" factory-bean="User3Factory" factory-method="getUser3"></bean> </beans>
測試代碼如下:
package introduction; import ioc3.User3; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 測試配置方式實現IOC三種方法 * * @author 吳曉暢 * */ public class TestIoc { @Test public void testUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("myXml.xml"); //方法3:使用實例工廠創建對象--了解就好 User3 user3 = (User3) context.getBean("user3"); System.out.println(user3); } }
運行結果如下:

4. 注解方式實現
方式一:實現對象創建
創建測試類:UserBean1.java
/** * 采用注解方式完成ioc * * @author 吳曉暢 * */ //目前spring有四個注解,功能都是一樣的,都是創建對象用的 //@Component @Controller @Service @Repository @Component(value="userBean1")//這個相當於<bean id="user" class=""/> public class UserBean1 { public void add() { System.out.println("UserBean1....add"); } }
src下創建配置文件bean.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: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.xsd"> <!-- bean definitions here --> <!-- 開啟注解掃描 base-package寫的包名 如果類在多個包里面,那么寫的方式如下 ioc_bean1,ioc_bean2,ioc_bean3... 或者采用cn 這樣表示加載cn開頭的所有包 cn.ioc則表示加載 cn.ioc開頭的所有包 --> <!-- 到包里面掃描類、方法、屬性上面注解 --> <context:component-scan base-package="ioc_bean1"></context:component-scan> <!-- 只掃描屬性上面的注解 --> <!--<context:annotation-config></context:annotation-config> --> </beans>
測試代碼如下
package introduction; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import ioc_bean1.UserBean1; import ioc_bean1.UserService;; /** * 測試bean方式使用IOC * * @author 吳曉暢 * */ public class TestBean { @Test public void testUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //測試bean配置方式創建對象 UserBean1 userBean1 = (UserBean1) context.getBean("userBean1"); System.out.println(userBean1); userBean1.add(); } }
運行結果如下

方式二:bean配置方式注入對象屬性
創建測試類:UserDao.java
import org.springframework.stereotype.Component; //這一步相當於創建了UserDao對象 @Component(value="userDao") public class UserDao { public void add() { System.out.println("UserDao....add"); } }
編寫測試類UserService.java
package ioc_bean1; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; //@Service(value="userService")等同於@Service("userService") //這一步相當於創建了UserService對象 @Service(value="userService") public class UserService { //得到UserDao對象 使用注解方式時候不需要使用set方法,直接到UserDao對象上面使用注解,完成對象注入 //即@Autowired用於注入屬性 @Autowired private UserDao userDao; //這種方式與上面方式能達到同樣效果 常用的是下面這種 //name的值要與UserDao的注解的value一致 // @Resource(name="userDao") // private UserDao userDao; public void add() { System.out.println("UserService...add...."); userDao.add(); } }
src下配置方式與方式一一致
測試代碼如下:
package introduction; import ioc_bean1.UserBean1; import ioc_bean1.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; ; /** * 測試bean方式使用IOC * * @author 吳曉暢 * */ public class TestBean { @Test public void testUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //測試bean配置方式注入對象屬性 UserService userService = (UserService) context.getBean("userService"); userService.add(); } }
運行結果如下

溫馨提示:
上面注解方式需要在使用類上面加上@Component(value="userDao"),在對象變量上使用@Autowired才能實現。
方式三:配置文件與注解方式混合使用
創建測試類BookDao.java
package ioc_bean2; public class BookDao { public void book() { System.out.println("BookDao....book"); } }
創建測試類OrderDao.java
package ioc_bean2; public class OrderDao { public void buy() { System.out.println("OrderDao....buy"); } }
創建測試服務BookService.java,在該服務中通過注解方式注入對象屬性
package ioc_bean2; import javax.annotation.Resource; public class BookService { //得到BookDao和OrderDao的對象 @Resource(name="bookDao") private BookDao bookDao; @Resource(name="orderDao") private OrderDao orderDao; public void add() { System.out.println("service"); bookDao.book(); orderDao.buy(); } }
src下配置文件如下
<?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: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.xsd"> <!-- bean definitions here --> <!-- 開啟注解掃描 base-package寫的包名 如果類在多個包里面,那么寫的方式如下 ioc_bean1,ioc_bean2,ioc_bean3... 或者采用cn 這樣表示加載cn開頭的所有包 cn.ioc則表示加載 cn.ioc開頭的所有包 --> <!-- 到包里面掃描類、方法、屬性上面注解 --> <context:component-scan base-package="ioc_bean2"></context:component-scan> <!-- 配置對象 --> <bean id="bookService" class="ioc_bean2.BookService"></bean> <bean id="bookDao" class="ioc_bean2.BookDao"></bean> <bean id="orderDao" class="ioc_bean2.OrderDao"></bean> </beans>
測試代碼如下
package ioc_bean2; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import ioc1.User; import ioc2.User2; import ioc3.User3; public class TestMixBean { @Test public void testService() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); BookService bookService = (BookService) context.getBean("bookService"); bookService.add(); } }
運行結果如下

方式四:帶參數的屬性注入
創建數組、集合、properties屬性注入測試類Person.java
package property;
import java.util.List; import java.util.Map; import java.util.Properties; /** * 測試數組、集合、properties屬性注入 * * @author 吳曉暢 * */ public class Person { private String pName; private String[] arrs; private List<String> list; private Map<String, String> map; private Properties properties; public void setpName(String pName) { this.pName = pName; } public void setArrs(String[] arrs) { this.arrs = arrs; } public void setList(List<String> list) { this.list = list; } public void setMap(Map<String, String> map) { this.map = map; } public void setProperties(Properties properties) { this.properties = properties; } public void test1() { System.out.println("pName--"+pName); System.out.println("arrs--"+arrs); System.out.println("list--"+list); System.out.println("map--"+map); System.out.println("properties--"+properties); } }
創建構造方法注入屬性測試類PropertyDemo1.java
package property; /** * 通過構造方法注入屬性 * * @author 吳曉暢 * */ public class PropertyDemo1 { private String userName; public PropertyDemo1(String userName) { this.userName = userName; } public void test1() { System.out.println("demo1......"+userName); } }
創建set方法注入屬性測試類PropertyDemo2.java
package property; /** * 通過set方法注入屬性 * * @author 吳曉暢 * */ public class PropertyDemo2 { private String bookName; //set方法 該方法一定要符合set/get方法命名規則 public void setBookName(String bookName) { this.bookName = bookName; } public void demoBookName() { System.out.println("book..."+bookName); } }
對象屬性注入測試類UserDao.java
package property; /** * 對象屬性注入 * * @author 吳曉暢 * */ public class UserDao { public void add() { System.out.println("UserDao.....dao"); } }
對象屬性注入測試類UserService.java
package property; /** * 對象屬性注入 * * @author 吳曉暢 * */ public class UserService { //定義UserDao屬性 private UserDao dao; //定義set方法 public void setDao(UserDao dao) { this.dao = dao; } public void add() { System.out.println("UserService...service"); //使用dao對象 dao.add(); } }
src下配置文件myXml.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" > <!-- 本來在該配置文件中還有一個屬性name,其作用和id一樣,id屬性值不能包含特殊符號(比如@#),但是name屬性可以,不過name屬性是很早版本時候使用的,現在都被替換成id了 scope屬性,總共有以下的值,但是最主要用的是前兩個,后面兩個不用記得,在該配置文件中我們沒有寫scope屬性,默認使用的是singleton singleton:默認值、單例的 prototype:多例的: request:創建對象,把對象放在request域里面 session:創建對象,把對象放在session域里面 globalSession:創建對象,把對象放在globalSession域里面 --> <!-- 使用有參數構造注入屬性 --> <bean class="property.PropertyDemo1" id="demo"> <!-- 表示給userName屬性注入value為小王的值 --> <constructor-arg value="小王" name="userName"> </constructor-arg> </bean> <!-- 使用set方法注入屬性 --> <!--這一步相當於創建了 property.PropertyDemo2類的對象--> <bean class="property.PropertyDemo2" id="demo2"> <!-- 表示給userName屬性注入value為小王的值 --> <property value="易筋經" name="bookName"> </property> </bean> <!-- 注入對象類型的屬性 --> <!-- 配置UserService和UserDao的對象 --> <bean id="userDao" class="property.UserDao"></bean> <bean id="userService" class="property.UserService"> <!-- 注入dao對象 現在不要寫value屬性,因為上面是字符串,現在是對象,使用ref屬性,dao配置bean標簽中的id值--> <property name="dao" ref="userDao"></property> </bean> <!-- 注入復雜類型屬性-》包括數組、集合等 --> <bean id="person" class="property.Person"> <!-- 數組 --> <property name="arrs"> <list> <value>小王</value> <value>小馬</value> <value>小宋</value> </list> </property> <!-- list集合 --> <property name="list"> <list> <value>小奧</value> <value>小金</value> <value>小普</value> </list> </property> <!-- map集合 --> <property name="map"> <map> <entry key="aa" value="Lucy"></entry> <entry key="bb" value="Mary"></entry> <entry key="cc" value="Tom"></entry> </map> </property> <!-- properties --> <property name="properties"> <props> <prop key="driverclass">com.mysql.jdbc.Driver</prop> <prop key="username">root</prop> </props> </property> </bean> </beans>
測試代碼如下
package property; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 測試屬性注入 * * @author 吳曉暢 * */ public class TestIoc { @Test public void textUser() { //加載spring配置文件,根據內容創建對象 ApplicationContext context = new ClassPathXmlApplicationContext("myXml.xml"); //測試構造注入屬性的方法 //得到配置創建的對象 PropertyDemo1 demo1 = (PropertyDemo1)context.getBean("demo"); demo1.test1(); //測試set方法注入屬性值 PropertyDemo2 demo2 = (PropertyDemo2)context.getBean("demo2"); demo2.demoBookName(); //測試使用set方法注入對象屬性 UserService userService = (UserService) context.getBean("userService"); userService.add(); //使用set方法注入復雜屬性對象 Person person = (Person) context.getBean("person"); person.test1(); } }
運行結果如下
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment). log4j:WARN Please initialize the log4j system properly. demo1......小王 book...易筋經 UserService...service UserDao.....dao pName--null arrs--[Ljava.lang.String;@28ac3dc3 list--[小奧, 小金, 小普] map--{aa=Lucy, bb=Mary, cc=Tom} properties--{driverclass=com.mysql.jdbc.Driver, username=root} Process finished with exit code 0
三、IoC常見注解總結
- 創建對象(相當於:<bean id="" class="">)
(1)@Component
作用:把資源讓spring來管理。相當於在xml中配置一個bean。
屬性:value:指定bean的id。如果不指定value屬性,默認bean的id是當前類的類名。首字母小寫。
(2)@Controller @Service @Repository
他們三個注解都是針對一個的衍生注解,他們的作用及屬性都是一模一樣的。
他們只不過是提供了更加明確的語義化。
@Controller:一般用於表現層的注解。
@Service:一般用於業務層的注解。
@Repository:一般用於持久層的注解。
細節:如果注解中有且只有一個屬性要賦值時,且名稱是value,value在賦值是可以不寫。
- 用於注入數據(相當於:<property name="" ref=""> <property name="" value="">)
(1)@Autowired
作用:自動按照類型注入。當使用注解注入屬性時,set方法可以省略。它只能注入其他bean類型。當有多個類型匹配時,使用要注入的對象變量名稱作為bean的id,在spring容器查找,找到了也可以注入成功。找不到就報錯。
(2)@Resource
作用:直接按照Bean的id注入。它也只能注入其他bean類型。
屬性:name:指定bean的id。
(3)@Value
作用:注入基本數據類型和String類型數據的
屬性:value:用於指定值
四、項目源碼及參考資料下載
鏈接:https://pan.baidu.com/s/1RDBXQcBchtA9i-bg8Z1r4Q
提取碼:io8n