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


  
 技術分析之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對來讓目標對象的方法執行。

 


技術分析之:Spring框架的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">
            
        </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();
            }
        }

 


技術分析之通知類型
    
    1. 通知類型
        * @Before                -- 前置通知
        * @AfterReturing        -- 后置通知
        * @Around                -- 環繞通知(目標對象方法默認不執行的,需要手動執行
        * @After                -- 最終通知
        * @AfterThrowing        -- 異常拋出通知
    
    2. 配置通用的切入點
        * 使用@Pointcut定義通用的切入點 

  @Aspect
        public class MyAspectAnno {
            @Before(value="MyAspectAnno.fn()")
            public void log(){
                System.out.println("記錄日志...");
            }
            @Pointcut(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
            public void fn(){}
        }
    

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM