Spring AOP編程實戰

Spring框架的IOC功能之注解的方式


Spring框架的IOC之注解方式的快速入門

1. 步驟一:導入注解開發所有需要的jar包
    * 引入IOC容器必須的6個jar包
    * 多引入一個:Spring框架的AOP的jar包,spring-aop的jar包

2. 步驟二:創建對應的包結構,編寫Java的類
    * UserService           -- 接口
    * UserServiceImpl       -- 具體的實現類

3. 步驟三:在src的目錄下,創建applicationContext.xml的配置文件,然后引入約束。注意:因為現在想使用注解的方式,那么引入的約束發生了變化
    * 需要引入context的約束,具體的約束如下
        <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"> <!-- bean definitions here -->
            
        </beans>

4. 步驟四:在applicationContext.xml配置文件中開啟組件掃描
    * Spring的注解開發:組件掃描
        <context:component-scan base-package="com.itheima.demo1"/>
        
    * 注意:可以采用如下配置
        <context:component-scan base-package="com.itheima"/> 這樣是掃描com.itheima包下所有的內容

5. 步驟五:在UserServiceImpl的實現類上添加注解
    * @Component(value="userService")   -- 相當于在XML的配置方式中 <bean id="userService" class="...">

6. 步驟六:編寫測試代碼
    public class SpringDemo1 {
        @Test
        public void run1(){
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService us = (UserService) ac.getBean("userService");
            us.save();
        }
    }

Spring框架中Bean管理的常用注解

1. @Component:組件.(作用在類上)

2. Spring中提供@Component的三個衍生注解:(功能目前來講是一致的)
    * @Controller       -- 作用在WEB層
    * @Service          -- 作用在業務層
    * @Repository       -- 作用在持久層
    
    * 說明:這三個注解是為了讓標注類本身的用途清晰,Spring在后續版本會對其增強

3. 屬性注入的注解(說明:使用注解注入的方式,可以不用提供set方法)
    * 如果是注入的普通類型,可以使用value注解
        * @Value            -- 用于注入普通類型
    
    * 如果注入的是對象類型,使用如下注解
        * @Autowired        -- 默認按類型進行自動裝配
            * 如果想按名稱注入
            * @Qualifier    -- 強制使用名稱注入
    
    * @Resource             -- 相當于@Autowired和@Qualifier一起使用
        * 強調:Java提供的注解
        * 屬性使用name屬性

Bean的作用范圍和生命周期的注解

1. Bean的作用范圍注解
    * 注解為@Scope(value="prototype"),作用在類上。值如下:
        * singleton     -- 單例,默認值
        * prototype     -- 多例

2. Bean的生命周期的配置(了解)
    * 注解如下:
        * @PostConstruct    -- 相當于init-method
        * @PreDestroy       -- 相當于destroy-method

Spring框架整合JUnit單元測試

1. 為了簡化了JUnit的測試,使用Spring框架也可以整合測試
2. 具體步驟
    * 要求:必須先有JUnit的環境(即已經導入了JUnit4的開發環境)!!
    
    * 步驟一:在程序中引入:spring-test.jar
    * 步驟二:在具體的測試類上添加注解
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:applicationContext.xml")
        public class SpringDemo1 {
            
            @Resource(name="userService")
            private UserService userService;
            
            @Test
            public void demo2(){
                userService.save();
            }
        }

案例一:使用AOP技術對DAO層操作進行增強功能


需求分析

1. 使用AOP技術對DAO層操作進行增強功能

Spring框架的核心功能之AOP技術


AOP的概述

1. 什么是AOP的技術?
    * 在軟件業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程
    * AOP是一種編程范式,隸屬于軟工范疇,指導開發者如何組織程序結構
    * AOP最早由AOP聯盟的組織提出的,制定了一套規范.Spring將AOP思想引入到框架中,必須遵守AOP聯盟的規范
    * 通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術
    * AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型
    * 利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率

2. AOP:面向切面編程.(思想.---解決OOP遇到一些問題)
3. AOP采取橫向抽取機制,取代了傳統縱向繼承體系重復性代碼(性能監視、事務管理、安全檢查、緩存)

4. 為什么要學習AOP
    * 可以在不修改源代碼的前提下,對程序進行增強!!   

Spring框架的AOP的底層實現

1. Srping框架的AOP技術底層也是采用的代理技術,代理的方式提供了兩種
    1. 基于JDK的動態代理
        * 必須是面向接口的,只有實現了具體接口的類才能生成代理對象
    
    2. 基于CGLIB動態代理
        * 對于沒有實現了接口的類,也可以產生代理,產生這個類的子類的方式

2. Spring的傳統AOP中根據類是否實現接口,來采用不同的代理方式
    1. 如果實現類接口,使用JDK動態代理完成AOP
    2. 如果沒有實現接口,采用CGLIB動態代理完成AOP

JDK的動態代理(代碼了解,理解原理)

1. 使用Proxy類來生成代理對象的一些代碼如下:
    /**
     * 使用JDK的方式生成代理對象
     * @author Administrator
     */
    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;
        }
    }

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;
    }

Spring基于AspectJ的AOP的開發


AOP的相關術語

1. Joinpoint(連接點)   -- 所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點
2. Pointcut(切入點)        -- 所謂切入點是指我們要對哪些Joinpoint進行攔截的定義
3. Advice(通知/增強)    -- 所謂通知是指攔截到Joinpoint之后所要做的事情就是通知.通知分為前置通知,后置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
4. Introduction(引介) -- 引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期為類動態地添加一些方法或Field
5. Target(目標對象)     -- 代理的目標對象
6. Weaving(織入)      -- 是指把增強應用到目標對象來創建新的代理對象的過程
7. Proxy(代理)        -- 一個類被AOP織入增強后,就產生一個結果代理類
8. Aspect(切面)           -- 是切入點和通知的結合,以后咱們自己來編寫和配置的

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();
        }
    }

切入點的表達式

1. 再配置切入點的時候,需要定義表達式,重點的格式如下:execution(public * *(..)),具體展開如下:
    * 切入點表達式的格式如下:
        * execution([修飾符] 返回值類型 包名.類名.方法名(參數))
    
    * 修飾符可以省略不寫,不是必須要出現的。
    * 返回值類型是不能省略不寫的,根據你的方法來編寫返回值。可以使用 * 代替。
    * 包名例如:com.itheima.demo3.BookDaoImpl
        * 首先com是不能省略不寫的,但是可以使用 * 代替
        * 中間的包名可以使用 * 號代替
        * 如果想省略中間的包名可以使用 .. 
    
    * 類名也可以使用 * 號代替,也有類似的寫法:*DaoImpl
    * 方法也可以使用 * 號代替
    * 參數如果是一個參數可以使用 * 號代替,如果想代表任意參數使用 ..

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對來讓目標對象的方法執行。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,779評論 18 139
  • 什么是Spring Spring是一個開源的Java EE開發框架。Spring框架的核心功能可以應用在任何Jav...
    jemmm閱讀 16,500評論 1 133
  • 本章內容: 面向切面編程的基本原理 通過POJO創建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,175評論 0 9
  • 很少有人知道“大胡子”到底叫啥,只是看他有著滿臉的絡腮胡須,所以大家就都跟著叫了。大胡子一生未娶,獨來獨往的生活倒...
    追夢CEO閱讀 864評論 21 21
  • 你值錢嗎?我相信很多人乍一聽到這個問題會有點懵!什么叫我值錢嗎?大部分人可能是丈二和尚摸不著頭腦。其實很多時候...
    詩蒙閱讀 164評論 0 1