Java進階-17.Spring

一、Spring

1.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/EEfull-stack(一站式) 輕量級開源框架。EE開發分成三層結構:

WEB層            -- Spring MVC

業務層             -- Bean管理(IOC)

持久層             -- Spring的JDBC模板,ORM模板用於整合其他的持久層框架

2.Spring框架特點

方便解耦,簡化開發:Spring就是一個大工廠,可以將所有對象創建和依賴關係維護,交給Spring管理;

AOP編程的支持:Spring提供面向切面編程,可以方便的實現對程序進行權限攔截、運行監控等功能;

聲明對事務的支持:只需要通過配置就可以完成對事務的管理,而無需手動編程;

方便程序的測試:Spring對Junit4支持,可以通過註解方便的測試Spring程序;

方便集成各種優秀框架:Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持;

降低JavaEE API的使用難度:Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大降低。

3.IOC核心功能

1. 什麼是IOC的功能?

IoC-- Inverse of Control,控制反轉,將對象的創建權反轉給Spring,使用IOC可以解決程序耦合性高的問題。

2. 步驟一:下載Spring框架的開發包。

官網:http://spring.io/

下載地址:http://repo.springsource.org/libs-release-local/org/springframework/spring

3. 步驟二:創建JavaWEB項目,引入Spring的開發包。

Spring框架的IOC的功能,需要引入4個jar包:Beans、Core、Context、Expression Language

Spring框架也需要引入日誌相關2個jar包:com.springsource.org.apache.commons.logging-1.1.1.jar、                  com.springsource.org.apache.log4j-1.2.15.jar

4. 步驟三:創建對應的包結構,編寫Java的類,要注意:以後使用Spring框架做開發,都需要來編寫接口與實現類。

com.itcast.demo1

       UserService                      -- 接口

       UserServiceImpl              -- 具體的實現類

5. 步驟四:想把UserServiceImpl實現類的創建交給Spring框架來管理,需要創建Spring框架的配置文件,完成配置。

在src目錄下創建applicationContext.xml的配置文件,名稱是可以任意的,但是一般都會使用默認名稱。

引入spring的約束,需要先找到具體的約束頭信息:

     spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html

具體的約束如下:                

<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">

</beans>

完成UserService的配置

<bean id="userService" class="com.itcast.demo1.UserServiceImpl"/>

6. 步驟五:編寫測試程序,採用Spring框架的工廠方式來獲取到UserService接口的具體實現類!!

public void demo2(){

         // 使用Spring的工廠:

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 通過工廠獲得類:

       UserService userService = (UserService) applicationContext.getBean("userService");

       userService.sayHello();

}

4.Spring框架中的工廠

1)ApplicationContext接口

使用ApplicationContext工廠的接口,使用該接口可以獲取到具體的Bean對象,該接口下有兩個具體的實現類

ClassPathXmlApplicationContext        -- 加載類路徑下的Spring配置文件

FileSystemXmlApplicationContext      -- 加載本地磁盤下的Spring配置文件

2)BeanFactory工廠(是Spring框架早期的創建Bean對象的工廠接口,已經過時)

使用BeanFactory接口也可以獲取到Bean對象

public void run(){

          BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

          UserService us = (UserService) factory.getBean("us");

          us.sayHello();

}

3)BeanFactory和ApplicationContext的區別

BeanFactory                   -- BeanFactory採取延遲加載,第一次getBean時纔會初始化Bean

ApplicationContext         -- 在加載applicationContext.xml時候就會創建Bean對象實例,還提供:事件傳遞、Bean自動裝配、各種不同應用層的Context實現

5.Bean管理的配置文件

1)id屬性和name屬性的區別

id              -- 爲Bean管理對象命名,在約束中採用ID的約束,唯一,必須以字母開始,可以使用字母、數字、連字符、下劃線、句話、冒號,id不能出現特殊字符

name       -- 爲Bean管理對象命名,沒有采用ID的約束(瞭解),name可以出現特殊字符。<bean>沒有id的話,name可以做id使用

2)class屬性          -- Bean對象的全路徑

3)scope屬性         -- scope屬性代表Bean的作用範圍

singleton     -- 單例(默認值)

prototype    -- 多例,在Spring框架整合Struts2框架時,Action類也需要交給Spring做管理,把Action類配置成多例!!

request       -- 應用在Web項目中,每次HTTP請求都會創建一個新的Bean

session       -- 應用在Web項目中,同一個HTTP Session 共享一個Bean

globalsession  -- 應用在Web項目中,多服務器間的session

4)Bean對象的創建和銷燬的兩個屬性配置(瞭解)

Spring初始化bean或銷燬bean時,有時需要作一些處理工作,因此spring可以在創建和銷燬bean的時候調用bean的兩個生命週期方法:

      init-method             -- 當bean被載入到容器的時候調用init-method屬性指定的方法

      destroy-method      -- 當bean從容器中刪除的時候調用destroy-method屬性指定的方法

想查看destroy-method的效果,有如下條件:scope= singleton有效

web容器中會自動調用,但是main函數或測試用例需要手動調用(需要使用ClassPathXmlApplicationContext的close()方法,即使用applicationcontext的實現類)

<bean id="userService" class="it.dragon.UserServiceImpl" scope="singleton" init-method="init" destroy-method="destory">

二、依賴注入(DI)

1.DI的概念

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

2. DI(依賴注入)

如果UserServiceImpl的實現類中有一個屬性,可使用Spring框架的IOC功能,通過依賴注入把該屬性的值傳入進來。

<bean id="us" class="com.itheima.demo1.UserServiceImpl">

         <property name="uname" value="小風"/>

</bean>

3.屬性注入

1)對於類成員變量,常用的注入方式有兩種

構造函數注入

屬性setter方法注入

2)構造方法的注入方式

編寫Java的類,提供構造方法

public class Car {

           private String name;

           private double money;

           public Car(String name, double money) {

                     this.name = name;

                     this.money = money;

           }

 }

編寫配置文件

<bean id="car" class="com.itheima.demo4.Car">

           <constructor-arg name="name" value="大奔"/>

           <constructor-arg name="money" value="100"/>

</bean>

3)屬性的setter方法的注入方式

編寫Java的類,提供屬性和對應的set方法

編寫配置文件,配置文件的屬性用:<property name="cname" value="大奔"/>

4)如果Java類的屬性是另一個Java的類,使用ref進行注入

<property name="name" rel="具體的Bean的ID或者name的值"/>,例如:

<bean id="person" class="com.itheima.demo4.Person">

        <property name="pname" value="美美"/>

        <property name="car2" ref="car2"/>

</bean>

4.p名稱空間注入(瞭解)

1)步驟一:需要先引入 p 名稱空間

在schema的名稱空間中加入該行:xmlns:p="http://www.springframework.org/schema/p"

2)步驟二:使用p名稱空間的語法

         p:屬性名 = ""

         p:屬性名-ref = ""

3)步驟三:注意在類中需要使用setter方法,如果是構造方法,無法注入。

<bean id="person" class="com.itheima.demo4.Person" p:pname="老王" p:car2-ref="car2"/>

5.SpEL注入方式(瞭解)

SpEL:Spring Expression Language是Spring的表達式語言,有一些自己的語法

語法:#{SpEL}

    <bean id="person" class="com.itheima.demo4.Person">

             <property name="pname" value="#{'小風'}"/>

             <property name="car2" value="#{car2}"/>

    </bean>

還支持調用類中的屬性或者方法

<bean id="carl" class="com.springinaction.springidol.Instrumentalist">

    <property name="song" value="#{kenny.song}" />

</bean>

kenny 是 Bean Id 而 song 是屬性的名字,這樣配置就如同我們寫了如下的代碼:

Instrumentalist carl = new Instrumentalist();

carl.setSong(kenny.getSong());

6.集合、Properties注入

1)如果是數組或者List集合,注入配置文件的方式是一樣的

<bean id="collectionBean" class="com.itheima.demo5.CollectionBean">

        <property name="arrs">

                   <list>

                              <value>美美</value>

                               <value>小風</value>

                   </list>

        </property>

</bean>

2)如果是Set集合,注入的配置文件方式如下:

<property name="sets">

         <set>

                   <value>哈哈</value>

                   <value>呵呵</value>

          </set>

</property>

3)如果是Map集合,注入的配置方式如下:

<property name="map">

          <map>

                  <entry key="老王" value="38"/>

                   <entry key="鳳姐" value="38"/>

                  <entry key="如花" value="29"/>

          </map>

</property>

4)如果是properties屬性文件的方式,注入的配置如下:

private Properties pro;在實現類中有個properties屬性。

<property name="pro">

        <props>

                <prop key="uname">root</prop>

                <prop key="pass">123</prop>

        </props>

</property>

7.配置文件分開管理

兩個核心的配置文件,那麼加載這兩個配置文件的方式有兩種!

1)主配置文件中包含其他的配置文件:<import resource="applicationContext2.xml"/>

2)工廠創建的時候直接加載多個配置文件:ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");

三、Spring框架整合WEB

1. 創建JavaWEB項目,引入Spring的開發包。引入spring-web-4.2.4.RELEASE.jar。編寫具體的類和方法。

環境搭建好後,啓動服務器來測試項目,每訪問一次都會加載一次配置文件,這樣效率會非常非常慢

2. 解決上面的問題

將工廠創建好了以後放入到ServletContext域中,使用工廠的時候,從ServletContext中獲得。

ServletContextListener:用來監聽ServletContext對象的創建和銷燬的監聽器,當ServletContext對象創建的時候:創建工廠,將工廠存入到ServletContext。

配置監聽器,在web.xml中

<!-- 配置Spring的核心監聽器 -->

<listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:applicationContext.xml</param-value>

</context-param>

修改servlet的代碼

ServletContext servletContext = ServletActionContext.getServletContext();

 // 需要使用WEB的工廠的方式

WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

CustomerService cs = (CustomerService) context.getBean("customerService");

cs.save();

四、IOC功能之註解

1.入門

1.步驟一:導入註解開發所有需要的jar包

引入IOC容器必須的6個jar包,多引入一個Spring框架AOP的jar包:spring-aop-4.2.4.RELEASE.jar。

2. 步驟二:創建對應的包結構,編寫Java的類

UserService                     -- 接口

UserServiceImpl              -- 具體的實現類

3. 步驟三:在src的目錄下,創建applicationContext.xml的配置文件,然後引入約束。注意:因爲現在想使用註解的方式,那麼引入的約束髮生了變化:

<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">

</beans>

4. 步驟四:在applicationContext.xml配置文件中開啓組件掃描

<context:component-scan base-package="com.itheima"/> 這樣是掃描com.itheima包下所有的內容

5. 步驟五:在UserServiceImpl的實現類上添加註解

@Component(value="userService")

相當於在XML的配置方式中 <bean id="userService" class="...">

6. 步驟六:編寫測試代碼

public void run1(){

     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

     UserService us = (UserService) ac.getBean("userService");

      us.save();

}

2.常用註解

1)@Component:作用在類上

2)Spring中提供@Component的三個衍生註解:(功能目前來講是一致的)

@Controller            -- 作用在WEB層

@Service                -- 作用在業務層

 @Repository          -- 作用在持久層

這三個註解是爲了讓標註類本身的用途清晰,Spring在後續版本會對其增強

3)屬性注入的註解(使用註解注入的方式,可以不用提供set方法)

如果是注入的普通類型,可以使用value註解

@Value       -- 用於注入普通類型

例如:在name屬性上添加如下,

@Value(value = "gggg")

private String name;

如果注入的是對象類型,使用如下註解

@Autowired    -- 默認按類型進行自動裝配

如果想按名稱注入

@Qualifier       -- 強制使用名稱注入,即類上面使用什麼名稱,就需要使用什麼名稱才能注入

例如:

@Autowired

@Qualifier(value = "userDao")

private UserDao ud;

@Resource     -- 相當於@Autowired和@Qualifier一起使用,這是Java提供的註解,使用name屬性

例如:

@Resource(name = "userDao")

private UserDao ud;

3.Bean的作用範圍和生命週期的註解

1)Bean的作用範圍註解

@Scope(value="prototype"),作用在類上。

      singleton         -- 單例,默認值

      prototype         -- 多例

2)Bean生命週期的配置

@PostConstruct      -- 在類中方法上,相當於init-method

@PreDestroy           -- 在類中方法上,相當於destroy-method

4.Spring框架整合JUnit

1)爲了簡化了JUnit的測試,使用Spring框架也可以整合測試

2)具體步驟

必須先有JUnit的環境(即已經導入了JUnit4的開發環境)

步驟一:在程序中引入:spring-test-4.2.4.RELEASE.jar

步驟二:在具體的測試類上添加註解

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class SpringDemo1 {

       @Resource(name="userService")

       private UserService userService;

       @Test

       public void demo2(){

                 userService.save();

        }

}

五、AOP技術

1.AOP概述

在軟件業,AOP爲Aspect Oriented Programming的縮寫上:面向切面編程。AOP是一種編程範式,隸屬於軟工範疇,指導開發者如何組織程序結構。AOP最早由AOP聯盟的組織提出的,制定了一套規範。Spring將AOP思想引入到框架中,必須遵守AOP聯盟的規範。通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術,AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。AOP採取橫向抽取機制,取代了傳統縱向繼承體系重複性代碼(性能監視、事務管理、安全檢查、緩存)。

2.AOP底層實現

1)Srping框架的AOP技術底層也是採用的代理技術,代理的方式提供了兩種:

基於JDK的動態代理:必須是面向接口的,只有實現了具體接口的類才能生成代理對象

基於CGLIB動態代理:對於沒有實現了接口的類,也可以產生代理,產生這個類的子類的方式

2)Spring傳統AOP中根據類是否實現接口,來採用不同的代理方式

如果實現類接口,使用JDK動態代理完成AOP

如果沒有實現接口,採用CGLIB動態代理完成AOP

3.JDK的動態代理

1)使用Proxy類來生成代理對象

public class MyProxyUtils {

       public static UserDao getProxy(final UserDao dao) {

       // 使用Proxy類生成代理對象

       UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),dao.getClass().getInterfaces(), new InvocationHandler() {

       // 代理對象方法一執行,invoke方法就會執行一次

       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                   if("save".equals(method.getName())){

                           System.out.println("記錄日誌...");

                    }

                   // 讓dao類的save或者update方法正常的執行下去

                  return method.invoke(dao, args);

        }

});

     // 返回代理對象

    return proxy;

   }

}

2)使用代理對象

public void run1(){

// 使用工具類,獲取到代理對象

UserDao proxy = MyProxyUtils.getProxy(dao);

// 調用代理對象的方法 proxy.save(); proxy.update();

}

4.CGLIB的代理技術

1)引入CBLIB的開發包

如果想使用CGLIB的技術來生成代理對象,那麼需要引入CGLIB的開發的jar包,在Spring框架核心包中已經引入了CGLIB的開發包了。所以直接引入Spring核心開發包即可!

2)編寫相關的代碼

public static OrderDaoImpl getProxy(){

        // 創建CGLIB核心的類

        Enhancer enhancer = new Enhancer();

        // 設置父類

        enhancer.setSuperclass(OrderDaoImpl.class);

        // 設置回調函數

        enhancer.setCallback(new MethodInterceptor() {

        @Override

        public Object intercept(Object obj, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {

                 if("save".equals(method.getName())){

                         System.out.println("記錄日誌了...");

                  }

                 return methodProxy.invokeSuper(obj, args);

          }

        });

        // 生成代理對象

        OrderDaoImpl proxy = (OrderDaoImpl) enhancer.create();

        return proxy;

}

5.基於AspectJ的AOP的開發

1)AOP的相關術語

1. Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因爲spring只支持方法類型的連接點

2. Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義

3. Advice(通知/增強) : 所謂通知是指攔截到Joinpoint之後所要做的事情就是通知。通知分爲前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)

4. Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期爲類動態地添加一些方法或Field

5. Target(目標對象) :代理的目標對象

6. Weaving(織入) :是指把增強應用到目標對象來創建新的代理對象的過程

7. Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類

8. Aspect(切面) :是切入點和通知的結合,以後咱們自己來編寫和配置的

2)AspectJ的XML方式完成AOP的開發

1. 步驟一:創建JavaWEB項目,引入具體的開發的jar包

先引入Spring框架開發的基本開發包,再引入Spring框架的AOP的開發包

spring的傳統AOP的開發的包:spring-aop-4.2.4.RELEASE.jar、com.springsource.org.aopalliance-1.0.0.jar

aspectJ的開發包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar、spring-aspects-4.2.4.RELEASE.jar

2. 步驟二:創建Spring的配置文件,引入具體的AOP的schema約束

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

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.xsd">

3. 步驟三:創建包結構,編寫具體的接口和實現類

com.itheima.demo2

       CustomerDao              -- 接口

       CustomerDaoImpl       -- 實現類

4. 步驟四:將目標類配置到Spring中

<bean id="customerDao" class="com.itheima.demo3.CustomerDaoImpl"/>

5. 步驟五:定義切面類

public class MyAspectXml {

            // 定義通知

            public void log(){

                    System.out.println("記錄日誌...");

           }

}

6. 步驟六:在配置文件中定義切面類

<bean id="myAspectXml" class="com.itheima.demo3.MyAspectXml"/>

7. 步驟七:在配置文件中完成aop的配置

<aop:config>

       <aop:aspect ref="myAspectXml">

           <!-- 定義通知類型:切面類的方法和切入點的表達式 -->

           <aop:before method="log" pointcut="execution(public com.itheima.demo3.CustomerDaoImpl.save(..))"/>

        </aop:aspect>

</aop:config>

8. 完成測試

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

         public class Demo3 {

         @Resource(name="customerDao")

          private CustomerDao customerDao;

          @Test

           public void run1(){

                    customerDao.save();

                    customerDao.update();

                    customerDao.delete();

           }

}

6.切入點的表達式

在配置切入點的時候,需要定義表達式,重點的格式如下:execution(public *(..)),具體展開如下:

切入點表達式的格式如下:execution([修飾符] 返回值類型 包名.類名.方法名(參數))

修飾符可以省略不寫,不是必須要出現的,例如public。

返回值類型是不能省略不寫的,根據你的方法來編寫返回值。可以使用*代替。

包名例如:com.itheima.demo3.BookDaoImpl

        首先com是不能省略不寫的,但是可以使用*代替、中間的包名可以使用*號代替、如果想省略中間的包名可以使用 ..

類名也可以使用*號代替,也有類似的寫法:*DaoImpl

方法也可以使用*號代替

參數如果是一個參數可以使用*號代替,如果想代表任意參數使用 ..

7.AOP的通知類型

1. 前置通知

在目標類的方法執行之前執行。

配置文件信息:<aop:after method="before" pointcut-ref="myPointcut3"/>

應用:可以對方法的參數來做校驗

2. 最終通知

在目標類的方法執行之後執行,如果程序出現了異常,最終通知也會執行。

在配置文件中編寫具體的配置:<aop:after method="after" pointcut-ref="myPointcut3"/>

應用:例如像釋放資源

3. 後置通知

方法正常執行後的通知。

在配置文件中編寫具體的配置:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>

應用:可以修改方法的返回值

4. 異常拋出通知

在拋出異常後通知

在配置文件中編寫具體的配置:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>      

應用:包裝異常的信息

5. 環繞通知

方法的執行前後執行。

在配置文件中編寫具體的配置:<aop:around method="around" pointcut-ref="myPointcut2"/>

要注意:目標的方法默認不執行,需要使用ProceedingJoinPoint對來讓目標對象的方法執行。

public void around(ProceedingJoinPoint joinPoint){
        System.out.println("環繞通知1...");
        try {
            // 手動讓目標對象的方法去執行
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("環繞通知2...");
}

8.AOP技術(註解方式)

1. 步驟一:創建JavaWEB項目,引入具體的開發的jar包

先引入Spring框架開發的基本開發包,再引入Spring框架的AOP的開發包

2. 步驟二:創建Spring的配置文件,引入具體的AOP的schema約束

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:aop="http://www.springframework.org/schema/aop"

      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.xsd">

</beans>

3. 步驟三:創建包結構,編寫具體的接口和實現類

com.itheima.demo1

        CustomerDao                 -- 接口

        CustomerDaoImpl           -- 實現類

4. 步驟四:將目標類配置到Spring中

<bean id="customerDao" class="com.itheima.demo1.CustomerDaoImpl"/>

5. 步驟五:定義切面類

添加切面和通知的註解

@Aspect              -- 定義切面類的註解

通知類型(註解的參數是切入點的表達式)

@Before               -- 前置通知

@AfterReturing    -- 後置通知

@Around             -- 環繞通知

@After                 -- 最終通知

@AfterThrowing   -- 異常拋出通知     

具體的代碼如下

@Aspect

public class MyAspectAnno {

          @Before(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")

           public void log(){

                       System.out.println("記錄日誌...");

           }

}

6. 步驟六:在配置文件中定義切面類

<bean id="myAspectAnno" class="com.itheima.demo1.MyAspectAnno"/>

7. 步驟七:在配置文件中開啓自動代理

<aop:aspectj-autoproxy/>

8. 完成測試

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo1 {                        

          @Resource(name="customerDao")

           private CustomerDao customerDao;   

           @Test

            public void run1(){

                    customerDao.save();

                    customerDao.update();

            }

 }

六、JDBC模板技術

1.JDBC模板技術概述

1. Spring框架中提供了很多持久層的模板類來簡化編程,使用模板類編寫程序會變的簡單

2. 提供了JDBC模板,Spring框架提供的 JdbcTemplate類

3. Spring框架可以整合Hibernate框架,也提供了模板類  HibernateTemplate類

2.JDBC的模板類

1.步驟一:創建數據庫的表結構

create database spring_day03;

use spring_day03;

create table t_account(

      id int primary key auto_increment,

      name varchar(20),

      money double

);

2.引入開發的jar包

先引入IOC基本的6個jar包、再引入Spring-aop的jar包、最後引入JDBC模板需要的jar包、MySQL數據庫的驅動包、Spring-jdbc.jar、Spring-tx.jar

3.編寫測試代碼(自己來new對象的方式)

@Test

public void run1(){

           // 創建連接池,先使用Spring框架內置的連接池

        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName("com.mysql.jdbc.Driver");

         dataSource.setUrl("jdbc:mysql:///spring_day03");

         dataSource.setUsername("root");

         dataSource.setPassword("root");

         // 創建模板類

         JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

          // 完成數據的添加

         jdbcTemplate.update("insert into t_account values (null,?,?)", "測試",10000);

}

3.Spring框架來管理模板類

1. 剛纔編寫的代碼使用的是new的方式,應該把這些類交給Spring框架來管理。

2. 修改的步驟如下

步驟一:Spring管理內置的連接池

        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

                 <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

                 <property name="url" value="jdbc:mysql:///spring_day03"/>

                 <property name="username" value="root"/>

                 <property name="password" value="root"/>

        </bean>

步驟二:Spring管理模板類

         <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

                   <property name="dataSource" ref="dataSource"/>

         </bean>

步驟三:編寫測試程序

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo2 {                               

           @Resource(name="jdbcTemplate")

            private JdbcTemplate jdbcTemplate;

            @Test

             public void run2(){

                jdbcTemplate.update("insert into t_account values (null,?,?)", "測試2",10000);

            }

}

4.管理開源的連接池

1. 管理DBCP連接池

先引入DBCP的2個jar包:com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar、com.springsource.org.apache.commons.pool-1.5.3.jar

編寫配置文件

      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

                 <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

                  <property name="url" value="jdbc:mysql:///spring_day03"/>

                  <property name="username" value="root"/>

                  <property name="password" value="root"/>

      </bean>

2. 管理C3P0連接池

先引入C3P0的jar包:com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar

編寫配置文件

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

        <property name="driverClass" value="com.mysql.jdbc.Driver"/>

        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03"/>

        <property name="user" value="root"/>

        <property name="password" value="root"/>

</bean>

5.JDBC模板的簡單操作

1. 增刪改查的操作

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class SpringDemo3 {    

        @Resource(name="jdbcTemplate")

        private JdbcTemplate jdbcTemplate;                     

         @Test

          public void demo1(){

                   jdbcTemplate.update("insert into account values (null,?,?)", "冠希",10000d);

                   jdbcTemplate.update("update account set name=?,money =? where id = ?", "思雨",10000d,5);

                   jdbcTemplate.update("delete from account where id = ?", 5);

           }

          @Test

            // 查詢一條記錄

            public void demo4(){

                Account account = jdbcTemplate.queryForObject("select from account where id = ?", new BeanMapper(), 1);

                 System.out.println(account);

            }                        

            @Test

            // 查詢所有記錄

            public void demo5(){

                      List<Account> list = jdbcTemplate.query("select from t_account", new BeanMapper());

                      for (Account account : list) {

                               System.out.println(account);

                       }

           }

  }    

class BeanMapper implements RowMapper<Account>{

        public Account mapRow(ResultSet rs, int arg1) throws SQLException {

                Account account = new Account();

                account.setId(rs.getInt("id"));

                account.setName(rs.getString("name"));

                account.setMoney(rs.getDouble("money"));

                return account;

        }

}

6.事務管理

1. PlatformTransactionManager接口           -- 平臺事務管理器(真正管理事務的類)。該接口有具體的實現類,根據不同的持久層框架,需要選擇不同的實現類!

2. TransactionDefinition接口          -- 事務定義信息(事務的隔離級別,傳播行爲,超時,只讀)

3. TransactionStatus接口               -- 事務的狀態

4. 總結:上述對象之間的關係:平臺事務管理器真正管理事務對象,根據事務定義的信息TransactionDefinition 進行事務管理,在管理事務中產生一些狀態,將狀態記錄到TransactionStatus中。

PlatformTransactionManager接口中實現類和常用的方法

1)接口的實現類

如果使用的Spring的JDBC模板或者MyBatis框架,需要選擇DataSourceTransactionManager實現類

如果使用的是Hibernate的框架,需要選擇HibernateTransactionManager實現類

2)該接口的常用方法

void commit(TransactionStatus status)

TransactionStatus getTransaction(TransactionDefinition definition)

void rollback(TransactionStatus status)

TransactionDefinition

1)事務隔離級別的常量

static int ISOLATION_DEFAULT     -- 採用數據庫的默認隔離級別

static int ISOLATION_READ_UNCOMMITTED

static int ISOLATION_READ_COMMITTED

static int ISOLATION_REPEATABLE_READ

static int ISOLATION_SERIALIZABLE

2)事務的傳播行爲常量(不用設置,使用默認值)

先解釋什麼是事務的傳播行爲:解決的是業務層之間的方法調用!!

 PROPAGATION_REQUIRED(默認值) -- A中有事務,使用A中的事務.如果沒有,B就會開啓一個新的事務,將A包含進來.(保證A,B在同一個事務中),默認值!!

PROPAGATION_SUPPORTS         -- A中有事務,使用A中的事務.如果A中沒有事務.那麼B也不使用事務.

PROPAGATION_MANDATORY         -- A中有事務,使用A中的事務.如果A沒有事務.拋出異常.

PROPAGATION_REQUIRES_NEW(記)-- A中有事務,將A中的事務掛起.B創建一個新的事務.(保證A,B沒有在一個事務中)

PROPAGATION_NOT_SUPPORTED       -- A中有事務,將A中的事務掛起.

 PROPAGATION_NEVER          -- A中有事務,拋出異常.

PROPAGATION_NESTED(記)   -- 嵌套事務.當A執行之後,就會在這個位置設置一個保存點.如果B沒有問題.執行通過.如果B出現異常,運行客戶根據需求回滾(選擇回滾到保存點或者是最初始狀態)

7.搭建事務管理轉賬案例的環境

1. 步驟一:創建WEB工程,引入需要的jar包

IOC的6個包、AOP的4個包、C3P0的1個包、MySQL的驅動包、JDBC目標2個包、整合JUnit測試包

2. 步驟二:引入配置文件

引入配置文件:

引入log4j.properties

引入applicationContext.xml

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

          <property name="driverClass" value="com.mysql.jdbc.Driver"/>

          <property name="jdbcUrl" value="jdbc:mysql:///spring_day03"/>

          <property name="user" value="root"/>

          <property name="password" value="root"/>

</bean>

3. 步驟三:創建對應的包結構和類

com.itheima.demo1

        AccountService

        AccountServlceImpl

        AccountDao

        AccountDaoImpl

4. 步驟四:引入Spring的配置文件,將類配置到Spring中

<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">

</bean>

<bean id="accountDao" class="com.itheima.demo1.AccountDaoImpl">

</bean>

5. 步驟五:在業務層注入DAO ,在DAO中注入JDBC模板(強調:簡化開發,以後DAO可以繼承JdbcDaoSupport類)

<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">

          <property name="accountDao" ref="accountDao"/>

</bean>

<bean id="accountDao" class="com.itheima.demo1.AccountDaoImpl">

           <property name="dataSource" ref="dataSource"/>

</bean>

6. 步驟六:編寫DAO和Service中的方法

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

          public void outMoney(String out, double money) {

                   this.getJdbcTemplate().update("update t_account set money = money = ? where name = ?", money,out);

          }

         public void inMoney(String in, double money) {

                   this.getJdbcTemplate().update("update t_account set money = money + ? where name = ?", money,in);

         }

}

7. 步驟七:編寫測試程序.

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo1 {                      

          @Resource(name="accountService")

           private AccountService accountService;                       

           @Test

           public void run1(){

                    accountService.pay("冠希", "美美", 1000);

          }

}

8.Spring框架的事務管理的分類

1)Spring的編程式事務管理(不推薦使用)

通過手動編寫代碼的方式完成事務的管理(不推薦)

2)Spring的聲明式事務管理(底層採用AOP的技術)

通過一段配置的方式完成事務的管理(重點掌握註解的方式)

9.編程式的事務管理

1. 說明:Spring爲了簡化事務管理的代碼,提供了模板類 TransactionTemplate,所以手動編程的方式來管理事務,只需要使用該模板類即可!!

2. 手動編程方式的具體步驟如下:

步驟一:配置一個事務管理器,Spring使用PlatformTransactionManager接口來管理事務,只需要使用到他的實現類!!

<!-- 配置事務管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

          <property name="dataSource" ref="dataSource"/>

</bean>

步驟二:配置事務管理的模板

<!-- 配置事務管理的模板 -->

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

           <property name="transactionManager" ref="transactionManager"/>

</bean>

步驟三:在需要進行事務管理的類中,注入事務管理的模板

<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">

          <property name="accountDao" ref="accountDao"/>

          <property name="transactionTemplate" ref="transactionTemplate"/>

</bean>

步驟四:在業務層使用模板管理事務

// 注入事務模板對象

private TransactionTemplate transactionTemplate;

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

          this.transactionTemplate = transactionTemplate;

}

public void pay(final String out, final String in, final double money) {

          transactionTemplate.execute(new TransactionCallbackWithoutResult() {

          protected void doInTransactionWithoutResult(TransactionStatus status) {

          accountDao.outMoney(out, money);

          int a = 10/0;

          accountDao.inMoney(in, money);

          }

          });

}

10.聲明式事務管理

即通過配置文件來完成事務管理(AOP思想),分兩種: 基於AspectJ的XML方式、基於AspectJ的註解方式

11.基於AspectJ的XML方式(重點掌握)

1. 步驟一:恢復轉賬開發環境

2. 步驟二:引入AOP的開發包

3. 步驟三:配置事務管理器

<!-- 配置事務管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

           <property name="dataSource" ref="dataSource"/>

</bean>

4. 步驟四:配置事務增強

<!-- 配置事務增強 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">

       <tx:attributes>

       <!--

               name:綁定事務的方法名,可以使用通配符,可以配置多個。

               propagation :傳播行爲

               isolation:隔離級別

               read-only:是否只讀

               timeout:超時信息

               rollback-for:發生哪些異常回滾.

               no-rollback-for:發生哪些異常不回滾.

        -->

                  <!-- 哪些方法加事務 -->

                 <tx:method name="pay" propagation="REQUIRED"/>

        </tx:attributes>

</tx:advice>

5. 步驟五:配置AOP的切面

<!-- 配置AOP切面產生代理 -->

 <aop:config>

       <aop:advisor advice-ref="myAdvice" pointcut="execution(com.itheima.demo2.AccountServiceImpl.pay(..))"/>

</aop:config>

注意:如果是自己編寫的切面,使用<aop:aspect>標籤,如果是框架的,使用<aop:advisor>標籤。

6. 步驟六:編寫測試類

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext2.xml")

public class Demo2 { 

          @Resource(name="accountService")

           private AccountService accountService;

           @Test

            public void run1(){

                   accountService.pay("冠希", "美美", 1000);

            }

}

12.基於AspectJ的註解方式(重點掌握,最簡單的方式)

1.步驟一:恢復轉賬的開發環境

2.步驟二:配置事務管理器

<!-- 配置事務管理器  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

           <property name="dataSource" ref="dataSource"/>

</bean>

3.步驟三:開啓註解事務

<!-- 開啓註解事務 -->

<tx:annotation-driven transaction-manager="transactionManager"/>

4.步驟四:在業務層的類上添加一個註解:@Transactional

5.編寫測試類

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext3.xml")

public class Demo3 {                     

       @Resource(name="accountService")

        private AccountService accountService;

        @Test

        public void run1(){

                  accountService.pay("冠希", "美美", 1000);

        }

}

七、SSH三大框架整合

1.jar包

1. Struts2框架

    struts-2.3.24\apps\struts2-blank\WEB-INF\lib\*.jar            -- Struts2需要的所有jar包

    struts2-spring-plugin-2.3.24.jar                                          ---Struts2整合Spring的插件包

2. Hibernate框架

                  hibernate-release-5.0.7.Final\lib\required\*.jar                   -- Hibernate框架需要的jar包

                  slf4j-api-1.6.1.jar                                                                                   -- 日誌接口

                  slf4j-log4j12-1.7.2.jar                                                                           -- 日誌實現

                  mysql-connector-java-5.1.7-bin.jar                                                  -- MySQL的驅動包

3. Spring框架

                  IOC核心包

                  AOP核心包

                  JDBC模板和事務核心包

                  Spring整合JUnit測試包

                  Spring整合Hibernate核心包

                  Spring整合Struts2核心包

2.配置文件

1. Struts2框架

                  在web.xml中配置核心的過濾器

                          <filter>

                                   <filter-name>struts2</filter-name>

                                   <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

                          </filter>

                         

                          <filter-mapping>

                                   <filter-name>struts2</filter-name>

                                   <url-pattern>/*</url-pattern>

                          </filter-mapping>

                  在src目錄下創建struts.xml,用來配置Action

2. Hibernate框架

                  在src目錄創建hibernate.cfg.xml配置文件

                  在JavaBean所在的包下映射的配置文件

3. Spring框架

                  在web.xml配置整合WEB的監聽器

                          <listener>

                                   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

                          </listener>

                          <context-param>

                                   <param-name>contextConfigLocation</param-name>

                                   <param-value>classpath:applicationContext.xml</param-value>

                          </context-param>

                 

                  在src目錄下創建applicationContext.xml

                  在src目錄下log4j.proerties

3.整合Struts2框架

1. 導入CRM項目的UI頁面,找到添加客戶的頁面,修改form表單,訪問Action

2. 編寫CustomerAction接收請求,在struts.xml中完成Action的配置

                  <package name="crm" extends="struts-default" namespace="/">

                          <action name="customer_*" class="com.itheima.web.action.CustomerAction" method="{1}">                     

                          </action>

                  </package>     

3. 在Action中獲取到service(開發不會使用,因爲麻煩)

可以通過 WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext()); 來獲取,但是這種方式編寫代碼太麻煩了!!      

4. Spring整合Struts2框架的第一種方式(Action由Struts2框架來創建)

                  因爲導入的struts2-spring-plugin-2.3.24.jar 包自帶一個配置文件 struts-plugin.xml ,該配置文件中有如下代碼

                          <constant name="struts.objectFactory" value="spring" /> 開啓一個常量,如果該常量開啓,那麼下面的常量就可以使用

                          struts.objectFactory.spring.autoWire = name,該常量是可以讓Action的類來自動裝配Bean對象!!       

5. Spring整合Struts2框架的第二種方式(Action由Spring框架來創建)(推薦大家來使用的)

                  把具體的Action類配置文件applicatonContext.xml的配置文件中,但是注意:struts.xml需要做修改

                  applicationContext.xml

                          <bean id="customerAction" class="com.itheima.web.action.CustomerAction" scope="prototype">         

                  struts.xml中的修改,把全路徑修改成ID值

                          <action name="customer_*" class="customerAction" method="{1}">

                  第二種方式需要有兩個注意的地方

                          Spring框架默認生成CustomerAction是單例的,而Struts2框架是多例的。所以需要配置 scope="prototype"

                          CustomerService現在必須自己手動注入了

4.技術分析之Spring框架整合Hibernate框架(帶有hibernate.cfg.xml的配置文件。強調:不能加綁定當前線程的配置)

1. 編寫CustomerDaoImpl的代碼,加入配置並且在CustomerServiceImpl中完成注入

2. 編寫映射的配置文件,並且在hibernate.cfg.xml的配置文件中引入映射的配置文件      

3. 在applicationContext.xml的配置文件,配置加載hibernate.cfg.xml的配置

                  <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

                          <property name="configLocation" value="classpath:hibernate.cfg.xml"/>

                  </bean> 

4. 在CustomerDaoImpl中想完成數據的添加,Spring框架提供了一個HibernateDaoSupport的工具類,以後DAO都可以繼承該類!!

                  public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao {

                          public void save(Customer c) {

                                   System.out.println("持久層...");

                                   this.getHibernateTemplate().save(c);

                          }

                  }

                  <bean id="customerDao" class="com.itheima.dao.CustomerDaoImpl">

                          <property name="sessionFactory" ref="sessionFactory"/>

                  </bean>

5. 開啓事務的配置

                  先配置事務管理器,注意現在使用的是Hibernate框架,所以需要使用Hibernate框架的事務管理器

                          <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

                                   <property name="sessionFactory" ref="sessionFactory"/>

                          </bean>

                  開啓註解事務

                          <tx:annotation-driven transaction-manager="transactionManager"/>  

                  在Service類中添加事務註解

                          @Transactional

5.技術分析之Spring框架整合Hibernate框架(不帶有hibernate.cfg.xml的配置文件)

1. Hibernate配置文件中

數據庫連接基本參數(4大參數)

Hibernate相關的屬性

連接池

映射文件

2. 開始進行配置

先配置連接池相關的信息

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

           <property name="driverClass" value="com.mysql.jdbc.Driver"/>

           <property name="jdbcUrl" value="jdbc:mysql:///xxx"/>

           <property name="user" value="root"/>

           <property name="password" value="root"/>

</bean>

修改 LocalSessionFactoryBean 的屬性配置,因爲已經沒有了hibernate.cfg.xml的配置文件,所以需要修改該配置,注入連接池

<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

           <property name="dataSource" ref="dataSource"/>

</bean>

繼續在 LocalSessionFactoryBean 中配置,使用hibernateProperties屬性繼續來配置其他的屬性,注意值是properties屬性文件

<!-- 配置其他的屬性 -->

<property name="hibernateProperties">

        <props>

             <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>

             <prop key="hibernate.show_sql">true</prop>

             <prop key="hibernate.format_sql">true</prop>

             <prop key="hibernate.hbm2ddl.auto">update</prop>

       </props>

</property>

<!-- 配置映射 -->

<property name="mappingResources">

         <list>

               <value>com/itheima/domain/Customer.hbm.xml</value>

         </list>

</property>

6.技術分析之Hibernate的模板的常用的方法

1. 增刪改的操作

添加:save(Object obj);

修改:update(Object obj);

刪除:delete(Object obj);

2. 查詢的操作

查詢一條記錄:

Object get(Class c,Serializable id);

Object load(Class c,Serializable id);

3. 查詢多條記錄

List find(String hql,Object... args);

7.技術分析之延遲加載問題    

1. 使用延遲加載的時候,再WEB層查詢對象的時候程序會拋出異常!

原因是延遲加載還沒有發生SQL語句,在業務層session對象就已經銷燬了,所以查詢到的JavaBean對象已經變成了託管態對象!

注意:一定要先刪除javassist-3.11.0.GA.jar包(jar包衝突了)

2. 解決辦法非常簡單,Spring框架提供了一個過濾器,讓session對象在WEB層就創建,在WEB層銷燬。只需要配置該過濾器即可

但是:要注意需要在struts2的核心過濾器之前進行配置

<filter>

          <filter-name>OpenSessionInViewFilter</filter-name>

          <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>

</filter>

<filter-mapping>

          <filter-name>OpenSessionInViewFilter</filter-name>

          <url-pattern>/*</url-pattern>

</filter-mapping>        

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章