天天看點

Spring架構Spring架構

Spring架構

spring的優點:

1、友善解耦,簡化開發

Spring就是一個大工廠,可以将所有對象建立和依賴關系維護,交給Spring管理。

2、AOP程式設計的支援

Spring提供面向切面程式設計,可以友善的實作對程式進行權限攔截、運作監控等功能。

3、聲明式事物的支援

隻需要通過配置就可以完成對事物的管理,而無需手動程式設計。

4、友善程式的測試

Spring對Junit4支援,可以通過注解友善的測試Spring程式

5、友善內建各種優秀架構

Spring不排斥各種優秀的開源架構,其内部提供了對各種優秀架構(如:Struts、Hibernate、MyBatis等)的直接支援。

6、降低JavaEE API的使用難度

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

spring下載下傳位址

Spring 4.2官方下載下傳位址

面向接口程式設計:

如果直接用接口去new一個實作類那麼它就會與業務層産生聯系,(opc原則)是以有了Spring的工廠模式,為解決工廠與接口之間的耦合有了:工廠+反射+配置檔案	如:
<bean id="us" class="com.dao.userServiceImpl">
Spring就像是整個項目中裝配bean的大工廠,在配置檔案中可以指定使用特定的參數去調用實體類的構造方法來執行個體化對象。
           

Spring的核心思想是IoC(控制反轉),即不再需要程式員去顯式地

new

一個對象,而是讓Spring架構幫你來完成這一切。

Spring架構Spring架構
Spring架構Spring架構
Spring架構Spring架構
package com.spring2.ioc.demo1;

public class UserServiceImpl implements UserService{
    @Override
    public void sayHello() {
        System.out.println("Hello Spring");
    }
}
//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">
    <!--UserService的建立權交給了Spring-->
    <bean id="userService1" class="com.spring2.ioc.demo1.UserServiceImpl">
            <!--設定屬性-->
        <property name="name" value="張三"/>
    </bean>
</beans>
//使用:

    @Test
        /*
     * 用ClassPathXmlApplicationContext讀取磁盤的配置檔案
     * */
    public void dome2(){
        //建立Spring的工廠
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
   
        //通過工廠擷取類
        UserService userService=(UserService) applicationContext.getBean("userService1");
        userService.sayHello();
    }
             @Test
    /*
    * 用FileSystemXmlApplicationContext讀取磁盤系統中的配置檔案
    * */
    public void demo3(){
        //建立Spring的工廠
        ApplicationContext applicationContext1=new FileSystemXmlApplicationContext("D:\\Javaprogram\\spring2_ico\\src\\main\\resources\\applicationContext.xml");
        UserService userService=(UserService) applicationContext1.getBean("userService1");
        userService.sayHello();
    }
/*
*1、FileSystemXmlApplicationContext讀取磁盤系統中的配置檔案
*2、ClassPathXmlApplicationContext在一個工程讀取配置檔案
*/
    /*
    * 傳統方式的工廠類:BeanFactory
    *  BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    * */
           

注:

<!-- 引入其它spring配置檔案 -->
	<import resource="spring/bean/applicationContext2.xml"/>
           

Spring IOC:

IOC Inverse of Control 反轉控制的概念,就是将原本在程式中手動建立對象的控制權,交由Spring架構管理

DI Dependency Injection 依賴注入的概念,就是在Spring建立這個對象的過程中,将這個對象依賴的屬性注入進去。

Spring的Bean管理(XML方式):

Spring的Bean管理(XML方式):

一、三種執行個體化Bean的方式:

1、使用類構造器執行個體化(預設無參數)

2、使用靜态工廠方法執行個體化(簡單工廠模式)

3、使用執行個體工廠方式執行個體化(工程方法模式)

實列:

<?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="bean1" class="com.spring2.ioc.demo2.Bean1"></bean>
    <!--第二種靜态方式-->
    <bean id="bean2" class="com.spring2.ioc.demo2.Bean2Faction"  factory-method="createBean2"></bean>
    <!--第三種工廠方式執行個體化-->
    <bean id="bean3Faction" class="com.spring2.ioc.demo2.Bean3Faction"/>
    <bean id="bean3" factory-bean="bean3Faction" factory-method="createBean3"/>
</beans>
           
(一)、id和 name、class

—— 一般情況下,裝配一個Bean時,痛毆制定一個id屬性作為Bean的名稱

—— id屬性在IOC容器中必須是唯一的(name和id的作用是一樣的,但id中不能有特殊字元,name中可包含特殊字元,4.0以前name可以重複)

—— 如果Bean的名稱中含有特殊字元,就需要使用name屬性

—— class用于設定一個類的完全路徑,主要作用是IOC容器生産類的執行個體。

Bean的作用域:

Spring架構Spring架構

scope屬性預設是:singleton

Spring容器中Bean的生命周期:

1、Spring初始化bean或銷毀bean時,有時需要做一些處理工作,是以spring可以在建立和銷

毀bean的時候調用bean的兩個生命周期方法。

當bean被載入到容器的時候調用init,當删除的時候調用destroy(scope=singleton有效)。

Spring架構Spring架構

注:一共有十一個過程,

1、執行個體化對象

2、設定(封裝 )屬性

3、如果Bean實作BeanNameAware 執行setBeanName

4、如果Bean實作BeanFactoryAware或者ApplicationContextAware設定工廠setBeanFactory或者上下文對象setApplicationContext

5、如果存在類實作BeanPostProcessor(後處理Bean),執行postProcessBeforeInitialization(在初始化之前就執行的方法)

(三和四需要去配置一下bean但可以不用配id)

6、如果Bean實作I逆天例子那個Bean執行afterPropertiesSet(滑鼠設定完成之後時執行)

7、調用指定初始化方法init

8、如果存在類實作BeanPostProcessor(處理Bean),執行postProcessAfterInitialization

9、執行業務處理(自己定義的方法)

10、如果Bean實作DisposableBean執行destroy(spring銷毀,接口:DisposableBean)

11、調用指定銷毀方法customerDestroy

業務增加:

public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        System.out.println("第八步:初始化後執行的方法");
        if ("UserDao".equals(beanName)){
            Object proxy=Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if ("select".equals(method.getName())){
                        System.out.println("權限校驗=============");
                        return method.invoke(bean,args);
                    }
                    return method.invoke(bean,args);
                }
            });
            return proxy;
        }
        return bean;
    }
           

Spring的屬性注入:

對于類成員變量,注入方式有三種:

——構造函數注入
——屬性setter方法注入
——接口注入
Spring支援前兩種
           
一、Spring 的屬性注入-構造方法注入:

1、通過構造方法注入Bean的屬性或依賴的對象,它保證了Bean執行個體在執行個體化就可以使用。

2、構造器注入在元素裡聲明的屬性。

<!--Bean的構造方法的屬性注入========================-->
    <bean id="user" class="com.spring2.ioc.demo4.User">
        <constructor-arg name="name" value="小王八羔子"/>
        <constructor-arg name="age" value="15"/>
    </bean>
           
二、set方法注入:

shiyongset方法注入,在Spring配置檔案中,通過設定注入的屬性。對象注入用 ref

<!--Bean的set方法的屬性注入========================-->
    <bean id="psera" class="com.spring2.ioc.demo4.Psera">
        <property name="name" value="網二"/>
        <property name="age" value="45"/>
        <property name="psera2" ref="psera2"/>
    </bean>
    <bean class="com.spring2.ioc.demo4.Psera2" id="psera2">
        <property name="name2" value="小三"/>
    </bean>
           
三、spring的屬性注入-p名稱空間:

——使用p命名空間

——為了簡化XML檔案配置,Spring從2.5開始引入一個新的p名稱空間

——p:<屬性名>=“XXX”引入常量值

——p:<屬性名>-ref=“XXX” 引用其他Bean對象

//先要在頭部加P空間
     xmlns:p="http://www.springframework.org/schema/p"
     
    <!--Bean的P标簽屬性注入========================-->
    <bean id="psera" class="com.spring2.ioc.demo4.Psera" p:name="張三" p:age="18" p:psera2-ref="psera2"/>
    <bean class="com.spring2.ioc.demo4.Psera2" id="psera2" p:name2="小二"/>
           
四、Spring的屬性注入——SpELl注入

——SpELl:spring expression language,spring 表達式語言,對依賴注入進行簡化

——文法:#{表達式}

——

如:

SpELl表達式語言:

文法:#{}

#{‘hello’}:使用字元串

#{beanId}:使用别一個bean

#{beanId.content.toUpperCase()}:使用指定名屬性,并使用方法

#{T(java.lang.Math).PI}:使用靜态字段或方法

<!--Bean的SpEl的屬性注入========================-->
    <bean class="com.spring2.ioc.demo4.Psera2" id="psera2">
        <property name="name2" value="#{'小三'}"/>
    </bean>
    <bean id="psera" class="com.spring2.ioc.demo4.Psera">
    <property name="name" value="#{'天翼'}"/>
    <property name="age" value="#{45}"/>
    <property name="psera2" value="#{psera2}"/>
    </bean>
           
五、複雜類型的屬性注入:

——數組類型的屬性注入

——List集合類型的屬性注入

——Set集合類型的屬性注入

——Map集合類型的屬性注入

——Properties類型的屬性注入

<!--Bean的集合屬性注入========================-->
    <bean id="listss" class="com.spring2.ioc.demo4.List_var">
        <!--數組-->
        <property name="sts">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <!--List集合-->
        <property name="list1">
            <list>
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </list>
        </property>
        <!--Map集合-->
        <property name="maps">
            <map>
                <entry key="name" value="張力"></entry>
                <entry key="age" value="18"></entry>
                <entry key="sex" value="男"></entry>
            </map>
        </property>
        <!--set集合-->
        <property name="sets">
            <set>
                <value>sss</value>
                <value>eee</value>
                <value>ttt</value>
            </set>
        </property>
        <!--props集合-->
        <property name="props">
            <props>
                <prop key="user">123</prop>
                <prop key="pws">1234</prop>
            </props>
        </property>
    </bean>
           

Spring的注解方式:

需要注入命名空間:

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
           

一、Spring2.5 引入使用注解去定義Bean

——@Component 描述Spring架構中Bean(如果不描述,會直接用類名注入,隻是會将類名第一個字母改為小寫)
@Component("psera2")
           

二、除了@Component外,Spring提供了3個功能基本和@Component等效的注解

——@Repository用于對DAO實作類進行表注
——@Service用于對Service實作類進行表注
——@Controller用于對Controller實作類進行表注
           

注:這三個注解是為了讓标注類本身的用途清晰,Spring在後續本版會對其增強

一般類型可以用:@Value(“值”)指派

//有ser方法時必須在set方法上
    @Value("汪汪")
    private String name2;
           

——使用@Autowired進行自動注入

——@Autowired預設按照類型進行注入

—如果存在兩個相同Bean類型相同,則按照名稱注入

——@Autowired注入時可以針對成員變量或者ser方法

——通過@Autowired的required屬性,設定一定要找到比對的Bean

——使用@Qualifier指定注入Bean的名稱

——Spring提供對JSR-250中定義@Resource标準注解的支援(等價于@Autowired和@Qualifier一起)

引用别的類(相當于實列化): @Autowired

@Autowired
   private Psera2 psera2;
   
   @Autowired
   @Qualifier("psera22")
   private Psera2 psera2;
   
  @Resource(name="psera22")
   private Psera2 psera2;
           

三、其它注解:

Spring架構Spring架構
Spring架構Spring架構

傳統XML配置和注解配置混合使用:

——XML方式的優勢:

- 結構清晰,易于閱讀

——注解方式的優勢:

- 開發便捷,屬性注入友善

——XML與注解的整合開發

- 1、引入context命名空間

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"

- 2、在配置檔案中添加context:component-scan标簽

隻需要開啟:注解掃描: <comtext:component-scan base-package=“掃描的範圍”/>

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:comtext="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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--開啟AspectJ的注解開發,自動代理=====-->
        <aop:aspectj-autoproxy/>
    <!--開啟ioc注解-->
        <comtext:component-scan base-package="com.spring.ioc.demo4"/>
</beans>
           

AOP(面向切面程式設計):

在軟體業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面程式設計,通過預編譯方式和運作期動态代理實作程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring架構中的一個重要内容,是函數式程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
           

——AOP采取橫向抽取機制,取代了傳統縱向繼承體系重複代碼(性能監視、事務管理、安全檢查、緩存)

一、什麼是AOP

Spring AOP使用純Java實作,不需要專門的編譯過程和類加載器,在運作期通過代理方式向目标類織入增強代碼
           

二、AOP相關術語

Joinpoint(連接配接點):所聞連接配接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring隻支援方法類型的連接配接點。

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

Advice(通知/增強):所謂通知是指攔截到Joinpoint之後所要做的事情就是通知。

通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)

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

Target(目标對象):代理的目标對象

Weaving(織入):是指把增強應用到目标對象來建立新的代理對象的過程。

spring采用動态代理織入,而AspectJ采用編譯期織入和類裝載期織入

Spring架構Spring架構

三、代理:

1、JDK動态代理

這種JDK動态代理可以增強實作了接口的類

Spring架構Spring架構

2、CGLIB生成代理:

——對于不使用接口的業務類,無法使用JDK動态代理。

——CGLIB采用非常底層位元組碼技術,可以為一個類建立子類,解決無接口代理問題。

這種方式需要引入spring的核心jar包(beans、expression、core、context)

Spring架構Spring架構

代理知識總結:

——Spring在運作期,生成動态代理對象,不需要特殊的編譯器

——Spring AOP的底層就是通過JDK動态代理或CGLib動态代理技術 為目标Bean執行橫向織入

1、若目标對象實作了若幹接口,spring使用JDK的java.lang.reflect.Proxy類代理

2、若目标對象沒有實作任何接口,spring使用CGLIB庫生成目标對象的子類。

——程式中應優先對接口建立代理,便于程式解耦維護

——标記為final的方法,不能被代理,因為無法進行覆寫

-JDK動态代理,是針對接口生成子類,接口中方法不能使用final修飾

-CGLib是針對目标類生成子類,是以類或方法不能使用final

——spring隻支援方法連接配接點,不提供屬性連接配接點.

SpringAOP增強類型

——AOP聯盟為通知Advice定義了org.aopalliance.aop.Interface.Advice

——Spring按照通知Advice在目标類方法的連接配接點位置,可以分為5類:

- 前置通知 org.springframework.aop.MethodBeforeAdvice

在目标方法執行前實施增強

- 後置通知 org.springframework.aop.AfterReturningAdvice

在目标方法執行後實施增強

- 環繞通知 org.aopalliance.intercept.MethodInterceptor

在目标方法執行前後實施增強

- 異常抛出通知 org.springframework.aop.ThrowsAdvice

在方法抛出異常後實施增強

- 引介通知 org.springframework.aop.IntroductionInterceptor

在目标類中添加一些新的方法和屬性(一般不管這種,因為spring AOP隻支援方法層面的增強)

SpringAOP切面類型:

—— Advisor:代表一半切面,Advice本身就是一個切面,對目标所有方法進行攔截

—— PointcutAdvisor:代表具有切點的切面,可以指定攔截目标哪些方法

—— IntroductionAdvisor:代表引介切面,針對引介通知而使用切面(這種一般不怎麼用)

Advisor切面案例

要引入spring幾個基本的jar包還要spring AOP聯盟的包(aopalliance)加spring aop

spring為我們提供了一個類生成代理:

—— ProxyFactoryBean常用可配置屬性

- target:代理的目标對象

- proxyInterfaces:代理要實作的接口

- 如果多個接口可以使用以下格式指派:

- interceptorNames:需要織入目标的Advice

- proxyTargetClass:是否對類代理而不是接口,設定為true時,使用CGLib代理

- singleton:傳回代理是否為單例,預設單例

- optimize:當設定為true時,強制使用CGLib

實作

一、普通Advisor

1、目标接口

public class UsermIp implements UserDao {
    @Override
    public void add() {
        System.out.println("add");
    }
    @Override
    public void updata() {
        System.out.println("updata");
    }
    @Override
    public void selcet() {
        System.out.println("selcet");
    }
    @Override
    public void del() {
        System.out.println("del");
    }
}
           

1、目标接口實作類

public class Mydavice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置增強==============");
    }
}
           

3、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">
        <!--配置目标類-->
        <bean id="user" class="com.spring.ioc.demo.UsermIp"/>
        <!--前置通知類型-->
        <bean id="davice" class="com.spring.ioc.demo.Mydavice"/>
        <!--AOP産生代理-->
        <bean id="student" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!--目标類-->
            <property name="target" ref="user"/>
            <!--實作的的接口-->
            <property name="proxyInterfaces" value="com.spring.ioc.UserDao"/>
            <!--攔截的名稱-->
            <property name="interceptorNames" value="davice"/>
        </bean>
</beans>
           

4、調用,測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:app.xml")
public class TestMothe {
//    @Autowired
//    @Qualifier(value = "user")
    @Resource(name = "student")
    private UserDao userDao;
    @Test
    public void test1(){
        userDao.add();
        userDao.selcet();
        userDao.updata();
        userDao.del();
    }
}
           

注:

@RunWith(SpringJUnit4ClassRunner.class) ======= 測試要導入JUnit4和spring-text的jar包

@ContextConfiguration(“classpath:app.xml”) ======= ApplicationContext app=new ClassPathXmlApplicationContext(“app.xml”);

二、普通PointcutAdvisor
  • 使用普通Advice作為切面,将對目标類所有方法進行攔截,不夠靈活,在實際開發中常用 帶有切點的切面
  • 常用PointcutAdvisor 實作類

    - DefaultPointcutAdvisor 最常用的切面類型,它可以通過任意Pointcut和Advice組合定義切面

    - JdkRegexpMethodPointcut 構造正規表達式切點

1、目标類

public class CustomerDao {
    public void find(){
        System.out.println("查詢使用者");

    }
    public void save(){
        System.out.println("儲存使用者");
    }
    public void uddate(){
        System.out.println("修改使用者");
    }
    public void del(){
        System.out.println("删除使用者");
    }
}
           

2、通知(環繞通知)

/*
* 環繞通知
* */
public class MyAroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("環繞前通知增強");
        Object obj=methodInvocation.proceed();
        System.out.println("環繞後通知增強");
        return obj;
    }
}
           

3、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">
    <!--配置目标類-->
    <bean id="customer" class="com.spring.ioc.demo2.CustomerDao"/>
    <!--配置通知-->
    <bean id="myaroundadvice" class="com.spring.ioc.demo2.MyAroundAdvice"/>
    <!--配置切入點-->
    <bean id="myaround" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--pattern中配置正規表達式:.任意字元    *任意次數-->
<!--        <property name="pattern" value=".*"/>-->
<!--        <property name="pattern" value=".*save.*"/>-->
        <property name="patterns" value=".*save.*,.*del.*"/>
        <property name="advice" ref="myaroundadvice"/>
    </bean>
    <!--配置産生代理-->
    <bean id="mycustomer" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="customer"/>
        <property name="proxyTargetClass" value="true"/>
        <property name="interceptorNames" value="myaround"/>
    </bean>
</beans>
           

4、調用是一樣的

自動建立代理

  • 前面的幾種代理,每個代理都是通過ProxyFactoryBean織入切面代理,在實際開發中,非常多的Bean每個都配置ProxyFactoryBean開發維護巨大。
  • 解決方案:自動建立代理

    - BeanNameAutoProxyCreator根據Bean名稱建立代理

    - DefaultAdvisorAutoProxyCreator 根據Advice本身包含資訊建立代理

    - AnnottionAwareAspectJAutoProxyCreator 基于Bean中的AspectJ注解進行自動代理

    一、基于Bean名稱的自動代理(BeanNameAutoProxyCreator):

<?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="customerDao" class="com.spring.ioc.demo2.CustomerDao"/>
    <bean id="UserDao" class="com.spring.ioc.demo.UsermIp"/>
    <!--配置通知-->
    <bean id="myaroundadvice" class="com.spring.ioc.demo2.MyAroundAdvice"/>
    <bean id="myaroundadvice2" class="com.spring.ioc.demo.Mydavice"/>
    <!--配置産生代理-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>//*通配符
        <property name="interceptorNames" value="myaroundadvice"/>
    </bean>
</beans>
           

二、可以配置切面點的(DefaultAdvisorAutoProxyCreator ):

<?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="customerDao" class="com.spring.ioc.demo2.CustomerDao"/>
    <bean id="UserDao" class="com.spring.ioc.demo.UsermIp"/>
    <!--配置通知-->
    <bean id="myaroundadvice" class="com.spring.ioc.demo2.MyAroundAdvice"/>
    <bean id="myaroundadvice2" class="com.spring.ioc.demo.Mydavice"/>
    <!--配置切面-->
    <bean id="myadvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="pattern" value="com.spring.ioc.demo2.CustomerDao.save"/>
        <property name="advice" ref="myaroundadvice"/>
    </bean>

    <!--配置産生代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
    </bean>
</beans>
           

AspectJ的使用:

開啟AOP注解: aop:aspectj-autoproxy/

  • AepectJ是一個基于JAVA語言的AOP架構
  • Spring2.0以後新增了對AspectJ切點表達式支援
  • @AspectJ是AspectJ1.5新增功能,通過JDK5注解技術,允許直接在Bean類中定義切面
  • 新版本Spring架構,建議使用AspectJ方式來開發AOP
  • 使用AspectJ需要導入表Spring AOP和AspectJ相關jar包
  • 如:
    • spring-aop
    • com.springsource.org.aopalliance
    • spring-aspects
    • com.springsource.org.aspectj.weaver

@AspectJ提供不同的通知類型

  • @Before 前置通知,相當于BeforeAdvice
  • @AfterReturning後置通知,相當于AfterReturningAdvice
  • @Around 環繞通知,相當于MethodInterceptor(事務管理,功能最強的,能夠阻止目标方法執行)
  • @AfterThrowing 異常抛出通知,相當于ThrowAdvice
  • @After 最終final通知,不管是否異常,該通知都會執行
  • @DeclareParents 引介通知,相當于IntroductionInterceptdor(一般不用)
在通知中通過value屬性定義切面
  • 通過execution函數,可以定義切面的方法切入
  • 文法:
    • execution(<通路修飾符>?<放回類型><方法名>(<參數>)<異常>)
  • 例如:
    • 比對所有類public方法 execution(public * *(…))
    • 比對指定包下所有類方法 execution(* com.imooc.dao.*(…))
    • execution(* com.imooc.dao…*(…)) …*表示包、子孫包下所有類
    • 比對指定類所有方法 execution(* com.imooc.service.UserService.*(…))
    • 比對實作特定接口所有類方法

      execution(* com.imooc.dao.GenericDAO+.*(…))

    • 比對所有save開頭的方法 execution(* save*(…))

通過注解實作:

1、目标類:

package com.spring.ioc.demo4;
import org.springframework.stereotype.Component;
@Component(value = "user")
public class UserFmI {
    public void add() {
        System.out.println("add");
    }
    public void del() {
        System.out.println("del");
    }
    public void update() {
        System.out.println("update");
    }
    public void select() {
        System.out.println("select");
    }
}

           

2、切面類(通知類)

3、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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:comtext="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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--開啟AspectJ的注解開發,自動代理=====-->
        <aop:aspectj-autoproxy/>
    <!--開啟ioc注解-->
        <comtext:component-scan base-package="com.spring.ioc.demo4"/>
</beans>
           

一、@Before前置通知

  • 可以在方法中傳入JoinPoint對象,用來擷取切點資訊
@Before(value = "execution(* com.spring.ioc.demo4.UserFmI.*(..))")
    public void aVoid(JoinPoint joinPoint){
        System.out.println("前置通知"+joinPoint);
    }
           
Spring架構Spring架構

二、@AfterReturning前置通知

  • 通過returning屬性,可以定義方法放回值,作為參數
    Spring架構Spring架構
    三、@Around環繞通知
  • around方法的傳回值就是目标代理方法執行傳回值
  • 參數為ProceedingJoinPoint 可以調用攔截目标方法執行
@Around("execution(* com.spring.ioc.demo4.UserFmI.select(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞前置通知");
        Object org=proceedingJoinPoint.proceed();//執行目标方法
        System.out.println("環繞後置通知");
        return org;
    }
           

注意:如果不調用ProceedingJoinPoint的proceed方法,那麼目标方法就被攔截了

四、@AfterThrowing異常抛出通知

  • 通過設定throwing屬性,可以設定發生異常對象參數
@AfterThrowing( value = "execution(* com.spring.ioc.demo4.UserFmI.del(..))",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("異常通知"+e.getMessage());
    }
           

五、@After最終通知

  • 無論是否出現異常,最終通知總是會被執行的
@After("execution(* com.spring.ioc.demo4.UserFmI.del(..))")
    public void after1(){
        System.out.println("最終通知");
    }
           

通過@Pointcut為切點命名

  • 在每個通知内定義切點,會造成工作量大,不易維護,對于重複的切點,可以使用@Pointcut進行定義
  • 切點方法:private void 無參數方法,方法名為切點名
  • 當通知多個切點時,可以使用 || 進行連接配接
@Component(value = "advice")
@Aspect
public class Myadvice {
    @Before(value = "cp1()")
    public void aVoid(){
        System.out.println("前置通知");
    }
    @AfterReturning( value = "cp()||cp1()",returning = "redd")
    public void after(Object redd){
        System.out.println("後置通知"+redd);
    }
    @Around("cp2()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環繞前置通知");
        Object org=proceedingJoinPoint.proceed();//執行目标方法
        System.out.println("環繞後置通知");
        return org;
    }
    @AfterThrowing( value = "cp3()",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("異常通知"+e.getMessage());
    }
    @After("cp3()")
    public void after1(){
        System.out.println("最終通知");
    }

    @Pointcut("execution(* com.spring.ioc.demo4.UserFmI.update())")
    public void cp(){}
    @Pointcut("execution(* com.spring.ioc.demo4.UserFmI.add())")
    public void cp1(){}
    @Pointcut("execution(* com.spring.ioc.demo4.UserFmI.select())")
    public void cp2(){}
    @Pointcut("execution(* com.spring.ioc.demo4.UserFmI.del())")
    public void cp3(){}

}
           

通過XML實作

這就隻貼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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:comtext="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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--XML方式配置AOP-->
        <!--配置目标類-->
        <bean id="userIm" class="com.spring.ioc.demo5.CustromIm"/>
        <!--配置切面類-->
        <bean id="myadvice1" class="com.spring.ioc.demo5.Myadvice"/>
        <!--AOP的相關配置-->
        <aop:config>
            <!--配置切入點-->
            <aop:pointcut id="pointcut1" expression="execution(* com.spring.ioc.demo5.CustromIm.*(..))"/>
            <!--配置AOP的切面-->
            <aop:aspect ref="myadvice1">
                <!--前置通知-->
                <aop:before method="after" pointcut-ref="pointcut1"/>//method是切面增強的方法,pointcut-ref是切入點(就是為誰服務)
                <!--後置通知-->
                <aop:after-returning method="after" pointcut-ref="pointcut1" returning=""/>//後置可以傳回值;returning是傳回參數名稱
                <!--環繞通知-->
                <aop:around method="after" pointcut-ref="pointcut1"/>
                <!--最終通知-->
                <aop:after method="after" pointcut-ref="pointcut1"/>
                <!--異常通知-->
                <aop:after-throwing method="after" pointcut-ref="pointcut1"/>
            </aop:aspect>
        </aop:config>
</beans>
           

JDBC Template:

  • 使用Spring元件JDBC Template簡化持久化操作,它是在JDBC API之上提供的元件
    Spring架構Spring架構

一。建立項目:

  • Maven
    • MySQL驅動
    • Spring元件(core、beans、context、aop)
    • JDBC Template(jdbc、tx)
  • Spring配置
    • 資料源
    • JDBC Template

1、要引入的jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>untitled5</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.22</version>
        </dependency>
        <!--spring元件jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <!--JDBC、tx事務處理-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
                <!--測試包Junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>Test</scope>
        </dependency>
    </dependencies>

</project>
           

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!--連接配接資料庫-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--驅動類-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <!--資料庫位址(一般會指定資料庫的字元集(characterEncoding=utf-8"))-->
        <property name="url" value="jdbc:mysql://localhost:3306/mylstu?characterEncoding=utf-8"/>
        <!--資料庫賬号-->
        <property name="username" value="root"/>
        <!--資料庫密碼-->
        <property name="password" value="123456"/>
    </bean>
    <!--配置Template工具-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>
           

JDBC Template基本使用:

  • execute方法(一般用它建表)
  • update與batch Update方法(增删改)
  • query與queryXXX方法(查詢)
  • call方法(調用存儲過程的)

一、execute(一般用它建表)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class Test {
    @Resource(name = "jdbcTemplate")
    public JdbcTemplate jdbcTemplate;
    @org.junit.Test
    public void testExecute(){
        /*
        *通過JdbcTemplate的execute來執行DDL語句
        * */
        jdbcTemplate.execute("create table user1(id int,name varchar(20) )");
    }
}
           

二、update與batch Update方法(增删改)

  • Update方法
    • 對資料進行增删改操作
      Spring架構Spring架構

      Object[],Object…是傳入的參數

      例子:

//Update
    @org.junit.Test
    public void testUpdate(){
        String sql="insert into user1 values(?,?)";
        jdbcTemplate.update(sql,new Object[]{1,"小明"});
    }
           
  • batch Update方法
    • 批量增删改操作
      Spring架構Spring架構
      例子:
//batchUpdate
    @org.junit.Test
    public void testbatchUpdate(){
        String sql="insert into user1 values(?,?)";
        List<Object[]> list=new ArrayList<Object[]>();
        list.add(new Object[]{4,"小張"});
        list.add(new Object[]{5,"老王"});
        jdbcTemplate.batchUpdate(sql,list);
    }
           

三、query與queryXXX方法(查詢)

Spring架構Spring架構
//query
    @org.junit.Test
    public void query(){
        String sql="select count(*) from user1";
        int sum=jdbcTemplate.queryForObject(sql,Integer.class);
        System.out.println(sum);
    }
    //querylist
    @org.junit.Test
    public void querylist() {
        String sql = "select name from user1 where id=?";
        List<Object> sumlist = jdbcTemplate.queryForList(sql, Object.class, 1);
        System.out.println(sumlist);
    }
           
Spring架構Spring架構
Spring架構Spring架構
//querylist封裝成類對象(匿名内類)
    @org.junit.Test
    public void querylistBeas() {
        String sql = "select *from user1 where id>?";
        List<UserBean> sumlistBean = jdbcTemplate.query(sql, new RowMapper<UserBean>() {
            public UserBean mapRow(ResultSet resultSet, int i) throws SQLException {
                UserBean bean=new UserBean();
                bean.setId(resultSet.getInt("id"));
                bean.setName(resultSet.getString("name"));
                return bean;
            }
        }, 0);
        System.out.println(sumlistBean);
    }
    //考慮代碼重用性問題一般我們是這樣的
        //querylist封裝成類對象
    @org.junit.Test
    public void querylistBeas() {
        String sql = "select *from user1 where id>?";
        List<UserBean> sumlistBean = jdbcTemplate.query(sql, new UserBeanRoMapper(), 0);
        System.out.println(sumlistBean);
    }
    private class UserBeanRoMapper implements RowMapper<UserBean>{
        public UserBean mapRow(ResultSet resultSet, int i) throws SQLException {
            UserBean bean=new UserBean();
            bean.setId(resultSet.getInt("id"));
            bean.setName(resultSet.getString("name"));
            return bean;
        }
    }
           

JDBC Template的優缺點:

  • JDB Template是Spring架構對JDBC操作的封裝,簡單、靈活但不過強大
  • 實際應用中還需要和其它ORM架構混合使用
  • 優點:
    • 簡單(簡化了很多代碼)
    • 靈活(簡單的封裝,使用起來跟JDBC API是一樣的)
  • 缺點:
    • SQL與Java代碼參雜(對程式用的要求較高)
    • 功能不豐富(分頁查詢…)

持久化的特點

  • 必須(資料需要存儲…)
  • 機械化(規則簡單,資料中的字段一一對應的)

ROM

  • 對象-關系

Spring事務管理:

概念

  • 什麼是事務:
    • 事務一般特指資料庫事務(Database Transaction),是指作為一個程式執行單元執行的一系列操作,要麼完全執行,要麼完全不執行。
  • 事務的特性
    • 原子性(atomicity)結構上
      • 一個事務是一個不可分割的工作機關
    • 一緻性(consistency)業務合理性的角度
      • 事務必須是使資料庫從一個一緻性狀态變到另一個一緻性狀态
    • 隔離性(isolatiion)
      • 一個事務的執行不能被其他事務幹擾。(叢集并發,上鎖什麼的)
    • 持久性(durability)
      • 一個事務一旦送出,它對資料庫中資料的改變就應該是永久性的。

Mysql事務處理

一、基本規則:

- MySQL中隻有使用了Innodb資料庫引擎的資料庫或表才支援事務。
	- show engines;  -- 檢視伺服器支援的引擎
	- default-storage-engine	=Innodb	-- my.ini修改預設引擎
- MySQL預設以自動送出(autocommit)模式運作
           
  • 語句
    • BEGIN(STARTTRANSACTION)
      • 顯式地開啟一個事務
    • COMMIT
      • 送出事務,并使已對資料庫進行的所有修改變為永久性的
    • ROLLBACK
      • 復原事務,并撤退正在進行的所有未送出的修改。

    二、事務并發問題:

    • 髒讀(解決方法:讓使用者隻能讀取永久性的資料)
    • 不可重複讀(解決方法:給事務加鎖(鎖行))
    • 幻讀(解決方法:也是加鎖,隻不過是鎖表)
      Spring架構Spring架構
Spring架構Spring架構
Spring架構Spring架構
Spring架構Spring架構

注意:問題解決的同時,工作效率會越來越低

  • 語句:
    • select @@tx_isolation;
      • 查詢預設隔離級别(預設是可重複讀)
    • set session transaction isolation level XXX
      • 設定目前會話隔離級别

JDBC事務處理

  • Connection接口
    • JDBC的事務處理是基于Connection的,JDBC通過Connection對象進行事務管理
    • JDBC預設事務處理行為是自動送出。
  • 事務相關方法
    • setAutoCommit
      • 設定自動送出
    • commit
      • 送出事務
    • rollback
      • 復原事務
  • JDBC事務隔離級别:
    • 隔離級别
      • TRANSACTION_NONE(不支援事務)
      • TRANSACTION_READ_UNCCMMITED
      • TRANSACTION_READ_COMMITTED
      • TRANSACTION_REPEATABLE_READ
      • TRANSACTION_SERIALIZABLE
    • 事務隔離級别設定
      • getTransactionIsolation
        • 擷取目前隔離級别
      • setTransactionIsoIation
        • 設定隔離級别

Spring事務處理API

Spring架構Spring架構

TransationDefinition接口

  • 隔離級别:
    • ISOLATION_DEFAULT(使用資料預設)
    • ISOLATION_READ_UNCOMMITTED
    • ISOLATION_READ_COMMITTED
    • ISOLATION_REPEATABLE_READ
    • ISOLATION_SERIALIABLE
  • 預設逾時
    • TIMEOUT_DEFAULT
      • 預設30秒
  • Spring事務傳播行為:
    • PROPAGATION_REQUIRED(預設的,用的最多的)
      • 支撐目前事務,如果目前沒有事務,就建立一個事務
    • PROPAGATION_SUPPORTS
      • 支援目前事務,如果目前沒有事務就以非事務方式執行
    • PROPAGATION_MANDATORY
      • 支援目前事務,如果目前沒有事務,就抛出異常。
    • PROPAGATION_REQUIRES_NEW
      • 建立事務,如果目前存在事務,把目前事務挂起。
    • PROPAGATION_NOT_SUPPORTED
      • 以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。
    • PROPAGATION_NEVER
      • 以非事務方式執行,如果目前存在事務,則抛出異常。
    • PROPAGATION_NESTED
      • 如果目前存在事務,則在嵌套事務内執行;如果目前沒有事務,就建立一個事務。

Spring 程式設計式事務處理

基于底層API的程式設計式事務管理:
- PlatformTransactionManager
	- TransactionDefintion
	- TransactionStatus
           
基于TransactionTemplate 的程式設計式事務管理
- TransactionTemplate
           

一、基于底層API的程式設計式事務管理:

實作類:

@Component
public class OrderServiceIm implements OrderService {
    @Autowired
    private OrderIm orderDao;
    @Autowired
    private ProderIm proderDao;
    @Autowired
    private PlatformTransactionManager transactionManager;//事務管理器對象
    @Autowired
    private TransactionDefinition transactionDefinition;//事務定義
    public void add(Order order) {
           // order.setConfirmDate();
            order.setState("待付款");
            TransactionStatus tstate = transactionManager.getTransaction(transactionDefinition);
            try {
                orderDao.insert(order);
                Goods goods=proderDao.selcet(Integer.parseInt(order.getGid()));
                goods.setInventorynum(goods.getInventorynum()-order.getNum());
                proderDao.update(goods);
                transactionManager.commit(tstate);
            }catch (Exception e){
                e.printStackTrace();
                transactionManager.rollback(tstate);
            }
    }
}
           

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc"/>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="transactionDefinition" class="org.springframework.transaction.support.DefaultTransactionDefinition">
        <!--設定行為等級-->
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
    </bean>
</beans>
           

二、基于TransactionTemplate 的程式設計式事務管理

實作類:

@Component
public class OrderServiceIm implements OrderService {
    @Autowired
    private OrderIm orderDao;
    @Autowired
    private ProderIm proderDao;
    @Autowired
    private PlatformTransactionManager transactionManager;//事務管理器對象
    @Autowired
    private TransactionTemplate transactionTemplate;//事務模版

    public void add(final Order order) {
        order.setState("待付款");
        transactionTemplate.execute(new TransactionCallback<Object>() {
            public Object doInTransaction(TransactionStatus transactionStatus) {
            try {
                orderDao.insert(order);
                Goods goods=proderDao.selcet(Integer.parseInt(order.getGid()));
                goods.setInventorynum(goods.getInventorynum()-order.getNum());
                proderDao.update(goods);
            }catch (Exception e){
                e.printStackTrace();
                transactionStatus.setRollbackOnly();//復原
            }
                return null;
            }
        });
    }
}
           

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc"/>
    <!--建立管理器-->
    <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>
</beans>
           

Spring 聲明式事務處理

概述:
- Spring的聲明式事務處理是建立在AOP的基礎之上的。其本質是對方法前後進行攔截,然後再目标方法開始之前建立或者加入一個事務,再執行完目标方法之後根據執行情況送出或者復原事務。
-  建議再開發中使用聲明式事務,是因為這樣可以是的業務代碼純粹幹淨,友善後期的代碼維護。
           
處理方式(第三種和第四種最常用):
  • 基于TransactionInterceptor的聲明式事務處理
  • 基于TransactionProxyFactoryBean的聲明式事務處理
  • 基于命名空間的聲明式事務管理
  • 基于@Transactional的聲明式事務管理

一、TransactionInterceptor:

實作類:

@Component(value = "OrderServiceIm1")
public class OrderServiceIm implements OrderService {
    @Autowired
    private OrderIm orderDao;
    @Autowired
    private ProderIm proderDao;

    public void add(final Order order) {
        order.setState("待付款");
                orderDao.insert(order);
                Goods goods=proderDao.selcet(Integer.parseInt(order.getGid()));
                goods.setInventorynum(goods.getInventorynum()-order.getNum());
                proderDao.update(goods);
    }
}
           

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc"/>
    <!--建立管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--攔截的對象(增強的目标)-->
    <bean id="OrderServiceImTarget" class="com.test.ioc.Bean.Service.impl.OrderServiceIm"/>
    <!--配置攔截器-->
    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <!--事務管機器-->
        <property name="transactionManager" ref="transactionManager"/>
        <!--事務的屬性-->
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="set**">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="**">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
    <!--生成代理-->
    <bean id="orderService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--目标-->
        <property name="target" ref="OrderServiceImTarget"/>
        <!--攔截器-->
        <property name="interceptorNames">
            <list>
                <idref bean="transactionInterceptor"/>
            </list>
        </property>
    </bean>
</beans>
           

二、TransactionProxyFactoryBean

  • 就是用一個bean配置實作代理和攔截器,該有的東西還是要用,隻是從結構上看緊湊一些。
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc"/>
    <!--建立管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--攔截的對象(增強的目标)-->
    <bean id="OrderServiceImTarget" class="com.test.ioc.Bean.Service.impl.OrderServiceIm"/>
    <bean id="orderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--事務管機器-->
        <property name="transactionManager" ref="transactionManager"/>
        <!--事務的屬性-->
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="set**">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="**">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
        <!--目标-->
        <property name="target" ref="OrderServiceImTarget"/>
    </bean>
</beans>
           

三、命名空間的聲明式事務管理

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc"/>
    <!--建立管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--切面-->
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <!--增強的方法-->
        <tx:attributes>
            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <!--切入點-->
        <aop:pointcut id="pointCut" expression="execution(* com.test.ioc.Bean.Service.impl.OrderServiceIm.*(..))"/>
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointCut"/>
    </aop:config>
</beans>
           

四、@Transactional的聲明式事務管理

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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <import resource="spring.xml"/>
    <context:component-scan base-package="com.test.ioc.Bean.Service.impl6"/>
    <!--建立管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
           

實作類:

@Component
public class OrderServiceIm implements OrderService {
    private OrderIm orderDao=new OrderIm();
    private ProderIm proderDao=new ProderIm();
    @Transactional(propagation = Propagation.REQUIRED)
    public void add(final Order order) {
        order.setState("待付款");
                orderDao.insert(order);
                Goods goods=proderDao.selcet(Integer.parseInt(order.getGid()));
                goods.setInventorynum(goods.getInventorynum()-order.getNum());
                proderDao.update(goods);
    }
}
           

開發需要注意的:

關于配置與注解

  • 配置
    • 非Java代碼
    • 便于後期維護
  • 注解
    • 靈活、精簡
  • 應用場合
    • 一處配置與多處注解
    • 代碼精簡
    • 注解需要複雜的非Java代碼

執行個體:

Spring架構Spring架構

繼續閱讀