本文簡要介紹了Spring,及Spring中IOC及DI的基本使用。 ...
一、Spring介紹
Spring 是一個開源框架,是為瞭解決企業應用程式開發複雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許您選擇使用哪一個組件,同時為 J2EE 應用程式開發提供集成的框架。簡單來說,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架。
Spring是2003年興起的一個輕量級的java框架, 由 Rod Johnson 在其編著的《Expert one on one J2EE design and development》一書中闡述的思想和理念衍生而來。
Spring 有兩個核心 IOC
& aop
-
IOC
IOC 的全稱是 Inversion Of Control 翻譯過來是控制反轉的意思。 把對象的創建工作交給框架來完成
UserService userService = new UserServiceImpl(); ---> 問框架要對象
-
AOP
AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程
1. IOC的演變
-
從早期的直接new具體類 ---> 面向介面編程
-
面向介面編程 --使用工廠
-
使用Spring來替代
2. Spring入門
-
導入jar包
beans
|code
|context
|expression
4個日誌jar包 , log4j.properties -
編寫業務邏輯類
public interface UserService { void save(); } public class UserServiceImpl implements UserService { @Override public void save(){ System.out.println("調用了UserServiceImpl的save方法~!~!"); } }
-
ml托管業務邏輯類
在src下,創建一個xml, 名字隨意。 applicationContext.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="us" class="com.pri.service.impl.UserServiceImpl"></bean> </beans>
-
創建工廠,問工廠要對象
public class MainTest { @Test public void testSave(){ /* UserService userService = new UserServiceImpl(); userService.save();*/ //1. 創建工廠 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. 問工廠要實例對象 UserService userService =(UserService) context.getBean("us"); //3. 調用方法 userService.save(); } }
3. 配置詳解
-
xml解釋
<!-- bean 標簽是用來告訴spring,需要幫忙創建什麼類的實例 id | name : 標識符 , 以後拿著id的值就能問spring要對應類的實例。 class : 托管類的全路徑 scope: 用於表示生成的實例模式 spring預設生成的實例是單例。 scope="prototype" 表示生成多例 init-method: 生成實例之後,調用的方法 destroy-method: 銷毀實例的時候調用的方法 --> <bean id="us" class="com.pri.service.impl.UserServiceImpl" scope="prototype" init-method="init" destroy-method="destroy"> </bean>
-
代碼解釋
public class MainTest { @Test public void testSave(){ /* UserService userService = new UserServiceImpl(); userService.save();*/ //1. 創建工廠 , 需要告訴工廠,xml文件在哪裡。 不會這麼寫 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //2. 問工廠要實例對象 , 可以讓工廠送過來 UserService userService =(UserService) context.getBean("us"); //3. 調用方法 userService.save(); //關閉工廠 以後一般不關閉工廠 ((AbstractApplicationContext) context).close(); } }
二、IOC實例化方式
把對象交給spring創建的方式
1. 無參構造方法【重點】
要求托管類的務必提供無參構造方法,當然以後可以配置讓spring走有參構造
-
代碼
public class UserServiceImpl implements UserService { //spring創建實例, 要求托管類預設提供無參構造方法。 @Override public void save(){ System.out.println("調用了UserServiceImpl的save方法~!~!"); } }
-
配置
<?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="us" class="com.pri.service.impl.UserServiceImpl"></bean> </beans>
2. 靜態工廠方法【瞭解】
要求提供工廠類,並且工廠的方法是靜態方法, 在方法裡面生成業務邏輯類的實例
-
代碼
public class StaticFactory { public static UserService getBean(){ System.out.println("要創建UserServiceImpl的實例了~~"); return new UserServiceImpl(); } }
-
xml
<!-- 我們也是拿著us去問spring工廠要實例, 它直接就調用了StaticFactory的getBean方法拿到實例,然後返回 --> <!-- 靜態工廠配置 --> <bean id="us" class="com.pri.factory.StaticFactory" factory-method="getBean"></bean>
3. 實例工廠方法【瞭解】
-
代碼
public class InstanceFactory { public UserService getBean(){ System.out.println("要創建UserServiceImpl的實例了~~"); return new UserServiceImpl(); } }
-
xml
<bean id="factory" class="com.pri.factory.InstanceFactory"/> <bean id="us" factory-bean="factory" factory-method="getBean"></bean>
後面的兩種工廠的配置,開發當中幾乎不會用。
三、依賴註入
-
什麼是依賴註入?
DI : 全稱是 dependency Injection 翻譯過來是依賴註入 本意是在實例化對象的時候,對它裡面的成員屬性進行值的註入。
public class UserServiceImpl{ private String name; //1. set方法 public void setName(String name){ this.name=name; } } UserServiceImpl us = new UserServiceImpl(); us.setName("zhangsan"); //現在實例的創建是工廠來完成,我們想讓工廠創建實例的時候,順便把成員變數給賦值了。
-
給成員變數賦值的方式【DI的方式】
①set方法
②有參構造
1. 依賴註入的方式【重點】
註入的方式有兩種: 有參構造 | set方法
1. 採用有參構造完成依賴註入
提供有參構造方法
-
代碼
public class UserServiceImpl implements UserService { private String address; public UserServiceImpl(String address) { super(); this.address = address; } @Override public void save(){ System.out.println("調用了UserServiceImpl的save方法~!~!=="+address); } }
-
xml
<bean id="us" class="com.pri.service.impl.UserServiceImpl" > <!-- 指定構造的參數, name: 參數的名稱, values: 參數的值 --> <constructor-arg name="address" value="深圳"/> </bean>
2. 採用set方法完成依賴註入
-
代碼
public class UserServiceImpl implements UserService { private String address; public void setAddress(String address) { this.address = address; } @Override public void save(){ System.out.println("調用了UserServiceImpl的save方法~!~!=="+address); } }
-
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="us" class="com.pri.service.impl.UserServiceImpl" > <property name="address" value="寶安"/> </bean> </beans>
2. 註入數據類型的演練
1. 集合類型
a. 數組類型
-
代碼
public class UserServiceImpl implements UserService{ private String [] address; public void setAddress(String [] address) { this.address = address; } ... }
-
xml
<property name="address" > <array> <value>北京1</value> <value>北京2</value> <value>我愛北京天安門,天安門很大</value> </array> </property>
b. list集合
-
代碼
public class UserServiceImpl implements UserService{ private List<String> address; public void setAddress(List<String> address) { this.address = address; } ... }
-
xml
<property name="address"> <list> <value>北京1</value> <value>北京2</value> <value>我愛北京天安門,天安門很大</value> </list> </property>
c. map集合
-
代碼
public class UserServiceImpl implements UserService{ private Map<String ,Object> address; public void setAddress( Map<String ,Object> address) { this.address = address; } ... }
-
xml
<property name="address"> <map> <entry key="地址1" value="北京1"/> <entry key="地址2" value="北京2"/> <entry key="地址3" value="北京3"/> </map> </property>
2. 對象類型
-
代碼
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save(){ System.out.println(" ==調用了UserServiceImpl的save方法~!~!=="); /*UserDao userDao =new UserDaoImpl(); //創建對象 ---》 IOC ----> bean標簽 userDao.save();*/ //1. 我們自己創建對象,然後自己用。 //2. 工廠創建對象,我們去問它要對象 //3. 工廠創建對象,讓工廠自己送過來對象。 --- 》 註入對象 userDao.save(); } }
-
xml
<!-- 讓spring創建UserServiceImpl的實例 --> <bean id="us" class="com.pri.service.impl.UserServiceImpl" > <!-- 讓spring調用UserServiceImpl的setUserDao的方法,並且把剛纔創建好的ud的那個實例當成參數,傳遞進去。 這就完成了對象的註入 --> <property name="userDao" ref="ud"></property> </bean> <!-- 讓spring創建UserDaoImpl的實例 --> <bean id="ud" class="com.pri.dao.impl.UserDaoImpl"></bean>
3.註入的xml寫法細節【瞭解】
依賴註入的方式已經固定化了,就是 有參構造 | set方法。 但是spring擔心程式員在xml的配置要寫的代碼很多,然後程式員就不喜歡用了。所以spring針對xml的註入,提出了兩種簡化寫法 : p 名稱空間 | c名稱空間
-
p 名稱空間
針對的是這個
<property name="" />
, 也就表明瞭代碼裡面聲明註入的方式是 set方式
<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="us" class="com.pri.service.impl.UserServiceImpl" p:address="北京"> </bean>
-
c 名稱空間
針對的是這個
<constructor-arg/>
, 也就要求我們的代碼聲明註入的方式必須是有參構造
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="us" class="com.pri.service.impl.UserServiceImpl" c:address="北京"> </bean>
-
SPEL 屬性註入
可以完成邏輯運算
<bean id="us" class="com.pri.service.impl.UserServiceImpl" > <property name="address" value="#{1>2}"/> </bean>
四、整合Servlet
1. 初步整合
在servlet裡面創建工廠、然後獲取實例對象
public class ServletDemo extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("調用了get方法~~~"); ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService us = (UserService)context.getBean("us"); us.save(); ((AbstractApplicationContext) context).close(); } }
2. 初步整合的問題
2個問題
1. 每次請求過來都會解析xml, 創建工廠。如果xml內容很多,就比較的耗時。
解決方法:
工具類 | 靜態代碼塊
2. 工廠創建的時機有點晚。 第一次使用的時候才會創建。
解決方法:
提前創建 --- 提前到項目發佈 --- 項目發佈之後,就會創建一個類的實例(ServletContext)-----ServletContextListner
a. 如果是我們自己處理的, 定義監聽器, 然後在監聽器裡面創建工廠 , 存儲工廠到一個地方去,以便所有的servlet都能使用到工廠。 servletContext.
b. 監聽器不用你們寫了,工廠創建的代碼不用你們寫了。放到servletcontext也不用寫了。 配置監聽器。
3. 進階整合
把上面出現的問題給解決掉 ,必須要導入額外的jar包
spring-web-xxx.jar
只要項目一發佈,就立即創建工廠,那麼我們必須的抓住項目發佈的這個契機。 以前在servlet階段,學過一種東西監聽器 ,可以監聽作用域對象的創建與銷毀 , SerlvetContext, 這是最大的作用域,全局只有一個對象。
-
在web.xml 中配置 監聽器 並且配置param 指定spring配置文件所在
<!-- 配置listener,目的就是讓項目發佈的回收,能夠創建工廠。但是創建工廠 需要解析xml文件,它預設回到/WEB-INF/applicationContext.xml 要是找不到就報錯,除非我們告訴它,xml文件在哪裡 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 告訴listener, 配置文件在哪裡 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
-
通過工具類獲取之前創建好的工廠
public class ServletDemo extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("調用了get方法~~~"); //ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); UserService us = (UserService)context.getBean("us"); us.save(); //((AbstractApplicationContext) context).close(); } ... }