Spring學習筆記(一)

Spring學習筆記(一)

這是一個沉澱的過程,大概第一次接觸Spring是在去年的這個時候,當初在實訓,初次接觸Java web,直接學習SSM框架(當是Servlet都沒有學),因而,養成了一個很很差的學習習慣,就是「照貓畫虎」。別人作什麼,照着樣子就是了,沒有任何的思考,這樣的學習習慣確定不會走太遠。如今我產生不少疑惑,這是什麼?爲何這麼作?如何作的更好?所以此次筆記的主題就是《這是什麼?html

1. spring框架概述

1.1 什麼是spring

  • Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由Rod Johnson 在其著做Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。它是爲了解決企業應用開發的複雜性而建立的。框架的主要優點之一就是其分層架構,分層架構容許使用者選擇使用哪個組件,同時爲 J2EE 應用程序開發提供集成的框架。Spring使用基本的JavaBean來完成之前只可能由EJB完成的事情。然而,Spring的用途不只限於服務器端的開發。從簡單性、可測試性和鬆耦合的角度而言,任何Java應用均可以從Spring中受益。Spring的核心是控制反轉(IoC)和麪向切面(AOP)。簡單來講,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架。 [^摘自]: (百度百科)
  • 輕量級:與EJB對比,依賴資源少,銷燬的資源少。
  • 分層: 一站式,每個層都提供的解決方案

1.2 spring由來

  • Expert One-to-One J2EE Design and Development
  • Expert One-to-One J2EE Development without EJB

1.3 spring核心

  • Spring的核心是 控制反轉(IoC) 面向切面(AOP)

1.4 spring優勢

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

1.5 spring體系結構

  • Spring框架是一個分層架構,它包含一系列的功能要素並被分爲大約20個模塊。這些模塊分爲Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation的測試部分,如圖所示:Spring體系結構圖
  • 核心容器:beans、core、context、expression

2. 入門案例:IoC

2.1 導入jar包

  • 在寫案例以前,須要導入5個jar包,4+1:4個核心(beans、core、context、expression) + 1個依賴(commons-loggins...jar) 5個jar包

2.2 目標類

  • 提供UserService接口和實現類
  • 提供UserService接口和實現類
    以前開發中,直接new一個對象便可。
    學習spring以後,將由Spring建立對象實例--> IoC 控制反轉(Inverse of Control)以後須要實例對象時,從spring工廠(容器)中得到,須要將實現類的全限定名稱配置到xml文件中。
public interface UserService {

        public void addUser();
    }
    public class UserServiceImpl implements UserService{
        @Override
        public void addUser() {
            System.out.println("add a User");
        }
    }

2.3 配置文件

  • 位置:任意,開發中通常在classpath下(src)
  • 名稱:任意,開發中經常使用applicationContext.xml
  • 內容:添加schema約束
    約束文件位置:spring-framework-xxx.RELEASE\docs\spring-framework-reference\html\xsd-config.html
<?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">
        <!-- 配置service 
            <bean> 配置須要建立的對象
                id :用於以後從spring容器得到實例時使用的
                class :須要建立實例的全限定類名
        -->
        <bean id="userService" class="com.springlearning.ioc.UserServiceImpl"></bean>
</beans>

2.4 測試

@Test
    public void demo02(){
        //從spring容器得到
        //1 得到容器
        String xmlPath = "com/springlearning/ioc/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        //2得到內容 --不須要本身new,都是從spring容器得到
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
    }

3. 入門案例:DI

  • DI Dependency Injection,依賴注入
    is a: 是一個,繼承。
    has a:有一個,成員變量,依賴。
class B{  
        private A a; //B類依賴A類  
    }

依賴:一個對象須要使用另一個對象
注入:經過setter方法進行另外一個對象實例設置java

  • 例如:
class BookServiceImpl{
        //以前開發:接口 = 實現類  (service和dao耦合)
    //private BookDao bookDao = new BookDaoImpl();
    //spring以後 (解耦:service實現類使用dao接口,不知道具體的實現類)
    private BookDao bookDao;
    setter方法
   }

模擬spring執行過程
建立service實例:BookService bookService = new BookServiceImpl() -->IoC <bean>
建立dao實例:BookDao bookDao = new BookDaoImple() -->IoC
將dao設置給service:bookService.setBookDao(bookDao); -->DI <property>web

3.1 目標類

  • 建立BookService接口和實現類
  • 建立BookDao接口和實現類
  • 將dao和service配置 xml文件
  • 使用api測試

3.1.1 dao

public interface BookDao {

    public void addBook();
}
public class BookDaoImpl implements BookDao {
    @Override
    public void addBook() {
        System.out.println("add a book");
    }
}

3.1.2 service

public interface BookService {
    void addBook();
}
public class BookServiceImpl implements BookService {
    //方式1: 以前 , 接口=實現類
    //private BookDao bookDao = new BookDaoImpl();
    //方式2: 接口+ setter
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    @Override
    public void addBook() {
        bookDao.addBook();
    }
}

3.2 配置文件

<?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">
    <!--
    模擬spring執行過程
        建立service實例:BookService bookService = new BookServiceImpl() IoC  <bean>
        建立dao實例:BookDao bookDao = new BookDaoImpl()         IoC
        將dao設置給service:bookService.setBookDao(bookDao);     DI   <property>

        <property> 用於進行屬性注入
            name: bean的屬性名,經過setter方法得到
                setBookDao ##> BookDao  ##> bookDao
            ref :另外一個bean的id值的引用
     -->
    <!-- 建立service -->
    <bean id="bookService" class="com.springlearning.di.BookServiceImpl">
        <property name="bookDao" ref="bookDao"></property>
    </bean>
    <!-- 建立dao實例 -->
    <bean id="bookDao" class="com.springlearning.di.BookDaoImpl"></bean>
</beans>

3.3 測試

@Test
public void demo01(){
    String xmlPath = "com/springlearning/di/beans.xml";
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) applicationContext.getBean("bookService");
    bookService.addBook();
}

4. 核心API

  • api總體瞭解,以後不使用,在學習過程須要。
    apispring

  • BeanFactory :這是一個工廠,用於生成任意bean。
    採起延遲加載,第一次getBean時纔會初始化Bean
  • ApplicationContext:是BeanFactory的子接口,功能更強大。(國際化處理、事件傳遞、Bean自動裝配、各類不一樣應用層的Context實現)。當配置文件被加載,就進行對象實例化。
    ClassPathXmlApplicationContext 用於加載classpath(類路徑、src)下的xml
    加載xml運行時位置 --> /WEB-INF/classes/...xml
    FileSystemXmlApplicationContext 用於加載指定盤符下的xml
    加載xml運行時位置 --> /WEB-INF/...xml
    經過java web ServletContext.getRealPath() 得到具體盤符
@Test
    public void demo02(){
        String xmlPath = "com/springlearning/di/beans.xml";
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
        BookService bookService = (BookService) beanFactory.getBean("bookService");
        bookService.addBook();
    }

5. 裝配Bean 基於XML

5.1 實例化方式

  • 3種bean實例化方式:默認構造、靜態工廠、實例工廠express

    5.1.1 默認構造

<bean id="" class="">  必須提供默認構造

5.1.2 靜態工廠

  • 經常使用與spring整合其餘框架(工具)
  • 靜態工廠:用於生成實例對象,全部的方法必須是static
<bean id=""  class="工廠全限定類名"  factory-method="靜態方法">
5.1.2.1 工廠
public class MyBeanFactory {
    /**
     * 建立實例
     * @return
     */
    public static UserService createService(){
        return new UserServiceImpl();
    }
}
5.1.2.2 spring配置
<?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">
    <!-- 將靜態工廠建立的實例交予spring
        class 肯定靜態工廠全限定類名
        factory-method 肯定靜態方法名
    -->
    <bean id="userService" class="com.springlearning.bean_xml.MyBeanFactory" factory-method="createService"></bean>
</beans>

5.1.3 實例工廠

  • 實例工廠:必須先有工廠實例對象,經過實例對象建立對象。提供全部的方法都是「非靜態」的。
5.1.3.1 工廠
/**
 * @ClassName:MyBeanFactory
 * @author: donkey-boy
 * @desc 實例工廠,全部方法非靜態
 * @date:2019/7/12 14:51
 */
public class MyBeanFactory {
    /**
     * 建立實例
     * @return
     */
    public UserService createService(){
        return new UserServiceImpl();
    }
}
5.1.3.2 spring 配置
<bean id="myBeanFactory" class="com.springlearning.bean_xml.MyBeanFactory"></bean>
    <!-- 得到userservice
        * factory-bean 肯定工廠實例
        * factory-bean 肯定普通方法
     -->
<bean id="userService" factory-bean="myBeanFactory" factory-method="createService"></bean>

5.2 Bean 種類

  • 普通bean:以前操做的都是普通bean。<bean id="" class="A"> ,spring直接建立A實例,並返回
  • FactoryBean:是一個特殊的bean,具備工廠生成對象能力,只能生成特定的對象。
    bean必須使用 FactoryBean接口,此接口提供方法 getObject() 用於得到特定bean。
    <bean id="" class="FB"> 先建立FB實例,使用調用getObject()方法,並返回方法的返回值
    FB fb = new FB();
    return fb.getObject();
  • BeanFactory 和 FactoryBean 對比?
    BeanFactory:工廠,用於生成任意bean。
    FactoryBean:特殊bean,用於生成另外一個特定的bean。例如:ProxyFactoryBean ,此工廠bean用於生產代理。<bean id="" class="....ProxyFactoryBean"> 得到代理對象實例。AOP使用

5.3 做用域

  • 做用域:用於肯定spring建立bean實例個數
    做用域編程

  • 取值:
    singleton 單例,默認
    prototype 多例,每執行一次getBean將得到一個實例。例如:struts整合spring,配置action多例。
  • 配置信息
<bean id="" class=""  scope="">
<bean id="userService" class="*" 
        scope="prototype" ></bean>

5.4 生命週期

5.4.1 初始化和銷燬

  • 目標方法執行先後執行後,將進行初始化或銷燬。
<bean id="" class="" init-method="初始化方法名稱"  destroy-method="銷燬的方法名稱">
5.4.1.1 目標類
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("add a User");
    }

    public void myInit(){
        System.out.println("初始化");
    }
    public void myDestroy(){
        System.out.println("銷燬");
    }
}
5.4.1.2 spring配置
<!--
    init-method 用於配置初始化方法,準備數據等
    destroy-method 用於配置銷燬方法,清理資源等
-->
<bean id="userService" class="com.springlearning.lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestroy"></bean>
5.4.1.3 測試
@Test
    public void demo02()  {
        String xmlPath = "com/springlearning/lifecycle/beans.xml";
        ClassPathXmlApplicationContext  applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.addUser();

        //要求:1.容器必須close,銷燬方法執行; 2.必須是單例的
//      applicationContext.getClass().getMethod("close").invoke(applicationContext);
        // * 此方法接口中沒有定義,實現類提供
        applicationContext.close();
    }

5.4.2 BeanPostProcessor 後處理Bean

  • spring 提供一種機制,只要實現此接口BeanPostProcessor,並將實現類提供給spring容器,spring容器將自動執行,在初始化方法前執行before(),在初始化方法後執行after() 。 配置<bean class="">
    後處理Beanapi

  • Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
  • spring提供工廠勾子,用於修改實例對象,能夠生成代理對象,是AOP底層。
    模擬
    A a =new A();
    a = B.before(a) --> 將a的實例對象傳遞給後處理bean,能夠生成代理對象並返回。
    a.init();
    a = B.after(a);
    a.addUser(); //生成代理對象,目的在目標方法先後執行(例如:開啓事務、提交事務)
    a.destroy()數組

5.4.2.1 編寫實現類
public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{
        System.out.println("前方法: "+ beanName);
        return  bean;
    }

    public Object postProcessAfterInitialization(final Object bean ,String beanName) throws  BeansException{
        System.out.println("後方法: "+ beanName);
        return Proxy.newProxyInstance(
                MyBeanPostProcessor.class.getClassLoader(),
                bean.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        System.out.println("-----開啓事物");
                        Object obj = method.invoke(bean,objects);
                        System.out.println("-----提交事物");
                        return obj;
                    }
                }
        );
    }
}
5.4.2.2 配置
<!-- 將後處理的實現類註冊給spring -->
    <bean class="com.springlearning.lifecycle.MyBeanPostProcessor"></bean>
  • 問題1:後處理bean做用某一個目標類,仍是全部目標類?
    全部
  • 問題2:如何只做用一個?
    經過「參數2」beanName進行控制

5.5 屬性依賴注入

  • 依賴注入方式:手動裝配 和 自動裝配
  • 手動裝配:通常進行配置信息都採用手動
    基於xml裝配:構造方法、setter方法
    基於註解裝配:
  • 自動裝配:struts和spring 整合能夠自動裝配
    byType:按類型裝配
    byName:按名稱裝配
    constructor構造裝配,
    auto: 不肯定裝配。

5.5.1 構造方法

5.5.1.1 目標類
public class User {

    private Integer id;
    private String username;
    private Integer age;

    public User(Integer id, String username) {
        super();
        this.id = id;
        this.username = username;
    }
    public User(String username,Integer age) {
        super();
        this.username = username;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
5.5.1.2 spring配置
<!-- 構造方法注入
        * <constructor-arg> 用於配置構造方法一個參數argument
            name :參數的名稱
            value:設置普通數據
            ref:引用數據,通常是另外一個bean id值

            index :參數的索引號,從0開始 。若是隻有索引,匹配到了多個構造方法時,默認使用第一個。
            type :肯定參數類型
        例如:使用名稱name
            <constructor-arg name="username" value="jack"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
        例如2:【類型type 和  索引 index】
            <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
            <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    -->
    <bean id="user" class="com.springlearning.constructor.User" >
        <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
        <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    </bean>

5.5.2 setter 方法

<!-- setter方法注入 
        * 普通數據 
            <property name="" value="值">
            等效
            <property name="">
                <value>值
        * 引用數據
            <property name="" ref="另外一個bean">
            等效
            <property name="">
                <ref bean="另外一個bean"/>
    
    -->
    <bean id="user" class="com.springlearning.setter.User" >
        <property name="id" value="1"></property>
        <property name="username">
            <value>gzy</value>
        </property>
        <property name="age" value="22" ></property>
        <property name="address" ref="address"></property>
    </bean>
    <bean id="address" class="com.springlearning.setter.Address">
        <property name="addr" value="huhhot"></property>
        <property name="tel" value="1234"></property>
    </bean>

5.5.3 P命名空間

  • 對「setter方法注入」進行簡化,替換<property name="屬性名">,而是在
    <bean p:屬性名="普通值" p:屬性名-ref="引用值">
  • p命名空間使用前提,必須添加命名空間
    xml
<bean id="user" class="com.springlearning.setter.User"
        p:username="gzy" p:age="22"
          p:address-ref="address"
    >
    </bean>
    <bean id="address" class="com.springlearning.setter.Address"
          p:addr="baotou" p:tel="123">
    </bean>

5.5.4 SpEL

  • <property>進行統一編程,全部的內容都使用value
    <property name="" value="#{表達式}">
    #{123}、#{'jack'} : 數字、字符串
    #{beanId} :另外一個bean引用
    #{beanId.propName} :操做數據
    #{beanId.toString()} :執行方法
    #{T(類).字段|方法} :靜態方法或字段
<bean id="user" class="com.springlearning.setter.User"
        p:username="gzy" p:age="22"
          p:address-ref="address"
    >
        <property name="id" value="#{123}"></property>
    </bean>
    <bean id="address" class="com.springlearning.setter.Address"
          p:addr="baotou" p:tel="123">
    </bean>

5.5.4 集合注入

<!-- 
        集合的注入都是給<property>添加子標籤
            數組:<array>
            List:<list>
            Set:<set>
            Map:<map> ,map存放k/v 鍵值對,使用<entry>描述
            Properties:<props>  <prop key=""></prop>  【】
            
        普通數據:<value>
        引用數據:<ref>
    -->
     <bean id="collData" class="com.springlearning.coll.CollData">
       <property name="array">
           <array>
               <value>alice</value>
               <value>bob</value>
               <value>carl</value>
               <value>Dick</value>
           </array>
       </property>
       <property name="list">
           <list>
               <value>Emma</value>
               <value>Ford</value>
               <value>Harris</value>
           </list>
       </property>
       <property name="set">
           <set>
               <value>張三</value>
               <value>李四</value>
               <value>王五</value>
           </set>
       </property>
       <property name="map">
           <map>
               <entry key="alice" value="愛麗絲"></entry>
               <entry>
                   <key><value>bob</value></key>
                   <value>鮑勃</value>
               </entry>
           </map>
       </property>
       <property name="properties">
           <props>
               <prop key="1">張三</prop>
               <prop key="2">李四</prop>
               <prop key="3">王五</prop>
           </props>
       </property>
   </bean>

6 裝配Bean 基於註解

  • 註解:就是一個類,使用@註解名稱
  • 開發中:使用註解 取代 xml配置文件。
  1. @Component取代<bean class="">
    @Component("id") 取代
  2. web開發,提供3個@Component註解衍生註解(功能同樣)取代<bean class="">
    @Repository :dao層
    @Service:service層
    @Controller:web層
  3. 依賴注入,給私有字段設置,也能夠給setter方法設置
    普通值:@Value("")
    引用值:
    方式1:按照【類型】注入
    @Autowired
    方式2:按照【名稱】注入1
    @Autowired
    @Qualifier("名稱")
    方式3:按照【名稱】注入2
    @Resource("名稱")
  4. 生命週期
    初始化:@PostConstruct
    銷燬:@PreDestroy
  5. 做用域
    @Scope("prototype") 多例
  • 註解使用前提,添加命名空間,讓spring掃描含有註解類
    xml
<!--組件掃描,掃描含有註解的類-->
    <context:component-scan base-package="com.springlearning.annotation"></context:component-scan>
  • 多是版本的緣由仍是其餘的緣由,我看的教學老師使用比較老的spring的相關jar包,大概是3.多的版本,我是用是5.0的版本,若是使用註解的方式,須要導入spring-aop-5.0.4.RELEASE.jar這個jar包,不然,測試會報錯java.lang.NoClassDefFoundError: org/springframework/aop/TargetSource。

筆記源自傳智播客Spring教學服務器

相關文章
相關標籤/搜索