Spring筆記

一、 Spring技術概述
1、什么是Spring : Spring是分層的JavaSE/EE full-stack(一站式) 輕量級開源框架
* JavaEE 程序在服務器端被分為三層 (Web層【表現層】、業務邏輯層、數據訪問層【集成層、持久層】)
* struts2 是表現層MVC的框架
* hibernate 是數據訪問層(持久層)的完全ORM框架

Spring框架中包括JavaEE 三層的 每一層的解決方案 (一站式)
* web層 SpringMVC
* 業務層 Spring Bean管理、AOP、事務管理
* 持久層 Spring JDBCTemplate、 ORM模塊(整合其他持久層框架)

2、 Spring的核心 : IoC 控制反轉 和 Aop 面向切面編程

  • 課程以3.2 版本講解

3、 Spring的由來 : 作者 Rod Johnson
2002年 Expert One-to-One J2EE Design and Development (分析J2EE開發 使用技術 EJB)
2004年 Expert One-to-One J2EE Development without EJB (客觀分析J2EE開發需要什么,推出一個新的框架, 后來Spring)

sun 公司在最早J2EE規范中,提供業務層解決方案 EJB

Spring出現就是為了解決JavaEE開發實際問題,輕量級, 相比EJB比較繁重、復雜的解決方案

4、 Spring 框架優點

  • 方便解耦,簡化開發
    Spring就是一個大工廠,可以將所有對象創建和依賴關系維護,交給Spring管理
  • AOP編程的支持
    Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能
  • 聲明式事務的支持
    只需要通過配置就可以完成對事務的管理,而無需手動編程
  • 方便程序的測試
    Spring對Junit4支持,可以通過注解方便的測試Spring程序
  • 方便集成各種優秀框架
    Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
  • 降低JavaEE API的使用難度
    Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低

5、Spring 包括哪些東西?

  • 核心技術 IoC 和 AOP
  • 數據訪問 (持久層解決方案)
  • Web層解決方案 SpringMVC
  • 集成 (整合其他開源框架)

未來五天課程: IoC 、 AOP 、 數據訪問、 集成

========================================================================================================================
二、 Spring 控制反轉案例快速入門
1、下載Spring最新開發包
http://www.springsource.org/download/community 下載spring3.2 的開發包
目錄結構
* docs 存放API和 規范文檔
* libs 開發jar包
* schemas 開發過程中需要導入xml的schema 約束

2、復制Spring開發 jar包到工程
復制核心容器包含jar包 (beans、core、context、expression language)
spring 的 jar包 需要依賴 commons-logging的 jar (commons-logging 類似 slf4j 是通用日志組件,需要整合 log4j )

  • 提示:spring3.0.X 版本 asm jar包 已經被合并到 spring core包中

3、理解IoC控制反轉和DI依賴注入
IoC Inverse of Control 反轉控制的概念,就是將原本在程序中手動創建HelloService對象的控制權,交由Spring框架管理,簡單說,就是創建HelloService對象控制權被反轉到了Spring框架

DI:Dependency Injection 依賴注入,在Spring框架負責創建Bean對象時,動態的將依賴對象注入到Bean組件

面試題: IoC 和 DI的區別?
IoC 控制反轉,指將對象的創建權,反轉到Spring容器 , DI 依賴注入,指Spring創建對象的過程中,將對象依賴屬性通過配置進行注入

4、編寫Spring核心配置文件
在src目錄創建 applicationContext.xml
在 docs\spring-framework-reference\html 找到 xsd-config.html

5、在程序中讀取Spring配置文件,通過Spring框架獲得Bean,完成相應操作
加載classpath (src):
new ClassPathXmlApplicationContext("applicationContext.xml");
加載磁盤路徑:
new FileSystemXmlApplicationContext("applicationContext.xml");
創建Spring 核心工廠對象

通過工廠的getBean 獲得配置實例對象 (IHelloService) applicationContext.getBean("helloService");

三、 Spring 工廠接口
BeanFactory 接口 和 ApplicationContext 接口區別 ?
* ApplicationContext 接口時 繼承 BeanFactory 接口 ,Spring 核心工廠是BeanFactory ,BeanFactory 采取延遲加載,第一次getBean時才會初始化Bean , ApplicationContext 是會在加載配置文件時 初始化Bean
* ApplicationContext是對BeanFactory擴展
國際化處理
事件傳遞
Bean自動裝配
各種不同應用層的Context實現

開發中基本都在使用ApplicationContext, web項目使用WebApplicationContext ,很少用到BeanFactory
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
IHelloService helloService = (IHelloService) beanFactory.getBean("helloService");
helloService.sayHello();

四、 在MyEclipse 配置Spring的xml文件提示
xml需要導入schema約束,約束指向網絡路徑
1、 聯網后,自動緩存路徑文件到本地,提供提示功能
2、 無法聯網 ,需要配置 xsd schema文件位置
到解壓spring/schemas/beans/spring-beans-3.2.xsd
選擇schema location 方式
復制網絡路徑 http://www.springframework.org/schema/beans/spring-beans.xsd

=========================================================================================================================
五、 IoC容器裝配Bean(xml配置方式)
1、 Spring 提供配置Bean 三種實例化方式
1)使用類構造器實例化(默認無參數)
<bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>
2)使用靜態工廠方法實例化(簡單工廠模式)
<bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>
3)使用實例工廠方法實例化(工廠方法模式)
<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

2、 Bean的其它屬性配置
<bean>元素的id屬性 和 name屬性的區別
早期Spring開發中 Bean的 id屬性 ,遵守xml語法 id約束
* id 的命名要滿足XML對ID屬性命名規范 必須以字母開始,可以使用字母、數字、連字符、下劃線、句話、冒號
使用name屬性,就可以使用很多特殊字符 , 早期在struts1 和 spring整合
<bean name="/login" class="....LoginAction" /> name中含有/ ,使用id會報錯

****** 如果元素沒有id只有name ,name 屬性值可以作為id 使用

<bean>元素scope屬性
    * scope="singleton" 單例 ,在Spring IoC容器中僅存在一個Bean實例 (默認的scope)
    * scope="prototype" 多例 ,每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時 ,相當于執行new XxxBean()
    * scope="request" 用于web開發,將Bean放入request范圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean
    * scope="session" 用于web開發,將Bean 放入Session范圍,在同一個Session 獲得同一個Bean
    * scope="globalSession" 一般用于Porlet應用環境 , 分布式系統存在全局session概念 ,如果不是porlet環境,globalSession 等同于Session
在開發中主要使用 scope="singleton"、 scope="prototype"

3、 Bean的生命周期
在配置 <bean> 元素,通過 init-method 指定Bean的初始化方法,通過 destroy-method 指定Bean銷毀方法
* destroy-method 只對 scope="singleton" 有效
* 銷毀方法,必須關閉ApplicationContext對象,才會被調用
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.close();

Bean的完整生命周期 (十一步驟)
1、instantiate bean對象實例化
2、populate properties 封裝屬性
3、如果Bean實現BeanNameAware 執行 setBeanName
4、如果Bean實現BeanFactoryAware 或者 ApplicationContextAware 設置工廠 setBeanFactory 或者上下文對象 setApplicationContext
5、如果存在類實現 BeanPostProcessor(后處理Bean) ,執行postProcessBeforeInitialization
6、如果Bean實現InitializingBean 執行 afterPropertiesSet
7、調用<bean init-method="init"> 指定初始化方法 init
8、如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization
9、執行業務處理
10、如果Bean實現 DisposableBean 執行 destroy
11、調用<bean destroy-method="customerDestroy"> 指定銷毀方法 customerDestroy

第三步和第四步,使Bean 了解Spring容器
第五步和第八步,使用BeanPostProcessor 就是鉤子函數,作用用來對Bean對象進行擴展

問題: 在userDAO對象所有方法上 添加運行時間監控
解決: 使用 BeanPostProcessor 完成

==========================================================================================================================
4、Spring的Bean屬性的依賴注入
支持 構造器注入 和 setter 方法注入

第一種 構造器注入 ,通過 <constructor-arg> 元素完成注入
<bean id="car" class="cn.itcast.spring.e_di.Car">

<constructor-arg index="0" type="java.lang.String" value="保時捷"></constructor-arg>
<constructor-arg index="1" type="double" value="1000000"></constructor-arg>
</bean>

第二種 setter方法注入, 通過<property> 元素完成注入
<bean id="car2" class="cn.itcast.spring.e_di.Car2">

<property name="name" value="寶馬"></property>
<property name="price" value="500000"></property>
</bean>

  • 使用 <property> 元素 ref屬性,引入另一個Bean對象,完成Bean之間注入
    <bean id="employee" class="cn.itcast.spring.e_di.Employee">
    <property name="name" value="張三"></property>
    <property name="car2" ref="car2"></property>
    </bean>

  • 名稱空間 p的使用 (Spring2.5 新特性)
    spring2.5版本 引入名稱空間p, 簡化屬性注入的配置
    p:<屬性名>="xxx" 引入常量值
    p:<屬性名>-ref="xxx" 引用其它Bean對象
    1) 引入p名稱空間
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    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">
    2) 改寫<property>注入為 p名稱空間注入
    <bean id="car2" class="cn.itcast.spring.e_di.Car2">

    <property name="name" value="寶馬"></property>
    <property name="price" value="500000"></property>
    </bean>

      <bean id="employee" class="cn.itcast.spring.e_di.Employee">
          <property name="name" value="張三"></property>
          <property name="car2" ref="car2"></property> <!-- ref引用其他Bean的id或者name -->
      </bean>
    

    改寫
    <bean id="car2" class="cn.itcast.spring.e_di.Car2" p:name="寶馬" p:price="1000000"></bean>
    <bean id="employee" class="cn.itcast.spring.e_di.Employee" p:name="李四" p:car2-ref="car2"></bean>

  • spring3.0之后引入 spEL 表達式
    1、 完成對象之間注入
    <property name="car2" ref="car2"></property>
    改寫為
    <property name="car2" value="#{car2}"></property>
    2、 使用另一個Bean屬性完成注入
    <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
    <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
    <property name="name" value="#{carInfo.name}"></property>
    </bean>
    3、 使用另一個Bean方法完成注入
    <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
    <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
    <property name="name" value="#{carInfo.name}"></property>
    <property name="price" value="#{carInfo.caculatePrice()}"></property>
    </bean>

5、 集合屬性的注入
spring提供專門標簽完成 List、Set、Map、Properties 等集合元素屬性注入

1) 注入List (數組)
<property name="hobbies">
<list>

<value>音樂</value>
<value>體育</value>
</list>
</property>

  1. 注入Set
    <property name="numbers">
    <set>
    <value>10</value>
    <value>6</value>
    <value>15</value>
    </set>
    </property>
    3) 注入Map
    <property name="map">
    <map>

    <entry key="name" value="itcast"></entry>
    <entry key="address" value="北京"></entry>
    </map>
    </property>

  2. 注入Properties

    • java.utils.Properties 類 繼承 java.utils.HashTable
      Properties key和value都是String類型
      例如:
      <property name="properties">
      <props>
      <prop key="company">傳智播客</prop>
      <prop key="pnum">100</prop>
      </props>
      </property>

6、 在Spring框架中引入多個XML配置文件
第一種 并列引入多個XML
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

第二種 引入總xml文件,在總xml文件引入 子xml文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
* 在applicationContext.xml 中
    <import resource="classpath:bean1.xml"/>
    <import resource="classpath:bean2.xml"/>

在開發中主要使用 第二種 , 將配置文件分離配置 便于維護管理

================================================================================================================================
六、Ioc容器裝配Bean(注解方式)
1、 搭建環境
導入jar 和 xml方式開發 是相同的

2、 使用注解方式進行Bean注冊
xml 方式: <bean id="" class="">
spring2.5版本 提供一組注解,完成Bean注冊
* @Component 描述Spring框架中Bean

第一步 編寫Class,在聲明上 添加 @Component
@Component("helloService")
// <bean id="helloService" class="...." />
public class HelloService {
}

第二步 編寫applicationContext.xml
通知Spring 注解類所在包
* 需要引入 context 名稱空間
<context:component-scan base-package="cn.itcast.spring.a_beandefinition"></context:component-scan>

spring2.5 引入@Component 等效三個衍生注解
* @Repository 用于對DAO實現類進行標注 (持久層)
* @Service 用于對Service實現類進行標注 (業務層)
* @Controller 用于對Controller實現類進行標注 (表現層)

3、 屬性依賴注入
1) 簡單屬性的注入 通過 @Value注解完成
@Service("userService")
public class UserService {
// 注入name屬性
@Value("itcast")
private String name;
}

2) 復雜屬性注入,通過@Autowired注解 完成Bean自動裝配
    @Autowired 默認按照類型進行注入

@Service("userService")
public class UserService {
    @Autowired
    // 復雜對象
    private UserDAO userDAO;
}

@Repository("userDAO")
public class UserDAO {
}

========================== @Value @Autowired注解都可以修飾 成員變量 或者 setter方法,如果修改成員變量,不需要提供setter方法
@Autowired注解 結合 @Qualifer注解 按照名稱注入
@Service("userService")
public class UserService {
@Autowired
@Qualifier("uDAO")
// 復雜對象
private UserDAO userDAO;
}

    @Repository("uDAO")
    public class UserDAO {

    }
3) 使用@Resource注解 完成復雜對象Bean裝配
    @Resource和@Autowired注解功能相似

@Autowired
@Qualifer("userDAO")
private UserDAO userDAO ;
等價于
@Resource(name="userDAO")
private UserDAO userDAO ;

4、Bean其它屬性設置
1) 指定Bean的初始化方法和銷毀方法(注解) <bean init-method="" destroy-method="" />
@PostConstruct 作用 init-method
@PreDestroy 作用 destroy-method
2) Bean的作用范圍 <bean scope="" />
@Scope 注解 ,默認作用域 singleton 單例

5、 Spring3.0 提供 注冊Bean的注解
@Configuration 指定POJO類為Spring提供Bean定義信息
@Bean 提供一個Bean定義信息

@Configuration
public class BeanConfig {
    // 提供兩個方法 獲得Car和Product對象
    @Bean(name = "car")
    public Car initCar() {
        Car car = new Car();
        car.setName("大眾");
        car.setPrice(10000);
        return car;
    }

    @Bean(name = "product")
    public Product showProduct() {
        Product product = new Product();
        product.setPname("空調");
        product.setPnum(100);
        return product;
    }
}

使用配置Bean 被Spring 掃描到 就可以了

6、 xml和注解混合使用
很多企業開發者 還是采用 xml作為主流配置

  • Bean 注冊 通過XML完成
  • 注入使用 @Autowired 注解完成

<context:annotation-config/> 啟用四個注解 使@Resource、@ PostConstruct、@ PreDestroy、@Autowired注解生效

結論 :
1、 xml配置 和 注解配置 效果完全相同
2、 如果Bean 來自第三方, 必須使用xml
3、 Spring3.0 Bean注冊方式, 使用比較少,主要用于Bean 構造邏輯及其復雜

===========================================================================================================================
七、在web項目中集成Spring
1、 直接在Servlet 加載Spring 配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloService helloService = (HelloService) applicationContext.getBean("helloService");
helloService.sayHello();
問題: 每次請求都會加載Spring環境,初始化所有Bean ,性能問題 ?。。?br> 解決方案一 : 將代碼放入Servlet init 中 , 無法保證所有Servlet都能使用 ApplicationContext
解決方案二 : ServletContext ----- tomcat啟動時, 加載Spring配置文件,獲得對象 ,放入ServletContext
* ServletCointextListener

2、導入spring-web.jar
保存 ContextLoaderListener 完成在Servlet初始化階段,加載Spring配置文件,將工廠對象放入 ServletContext

3、配置web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

  • 默認讀取 WEB-INF/applicationContext.xml
    配置 全局參數 contextConfigLocation 指定 配置文件位置
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

4、 修改Servlet代碼
從ServletContext中獲得 Spring工廠
第一種:
WebApplicationContext applicationContext = (WebApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
第二種:
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

八、Spring 整合 junit4 測試
1、 導入spring-test.jar
2、 編寫測試用例
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定配置文件位置
public class HelloServiceTest {
@Autowired
private HelloService helloService; // 注入需要測試對象

    @Test
    // 測試
    public void demo2() {
        helloService.sayHello(); // 調用測試方法
    }
}

=============================================================================================================

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,836評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,925評論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,193評論 2 7
  • 來源:關于Spring IOC (DI-依賴注入)你需要知道的一切作者:zejian Dao層(AccountDa...
    楊井閱讀 5,359評論 0 27
  • 媽媽家的純家雞,這個早讓我垂涎三尺了。盼了許久,今日因為事出有因想讓它們提前奉獻犧牲自己。于是,一大早和廣叔兩個人...
    燕紀事閱讀 281評論 0 1