1. 程式人生 > >使用AspectJ LTW(Load Time Weaving)【轉載】

使用AspectJ LTW(Load Time Weaving)【轉載】

在Java 語言中,從織入切面的方式上來看,存在三種織入方式:編譯期織入、類載入期織入和執行期織入。編譯期織入是指在Java編譯期,採用特殊的編譯器,將切面織入到Java類中;而類載入期織入則指通過特殊的類載入器,在類位元組碼載入到JVM時,織入切面;執行期織入則是採用CGLib工具或JDK動態代理進行切面的織入。
    AspectJ採用編譯期織入和類載入期織入的方式織入切面,是語言級的AOP實現,提供了完備的AOP支援。它用AspectJ語言定義切面,在編譯期或類載入期將切面織入到Java類中。
    AspectJ提供了兩種切面織入方式,第一種通過特殊編譯器,在編譯期,將AspectJ語言編寫的切面類織入到Java類中,可以通過一個Ant或Maven任務來完成這個操作;第二種方式是類載入期織入,也簡稱為LTW(Load Time Weaving)。
    使用AspectJ LTW有兩個主要步驟,第一,通過JVM的-javaagent引數設定LTW的織入器類包,以代理JVM預設的類載入器;第二,LTW織入器需要一個 aop.xml檔案,在該檔案中指定切面類和需要進行切面織入的目標類。

    設定-javaagent JVM引數的方法:
(1)在Eclipse下的設定:
執行類->右鍵單擊->Run As->Run...,可以在彈出的Run設定視窗設定該類的各項執行屬性,切換到Arguments Tab頁,在VM arguments中通過-javaagent指定AspectJ 織入器類包。-javaagent:E:\workspace\lib\spring2.5\aspectjweaver.jar
(2)在Tomcat下的設定
開啟<Tomcat_Home>\bin\catalina.bat,在該批處理檔案頭部新增以下的設定:
set JAVA_OPTS=-javaagent:E:\workspace\lib\spring2.5\aspectjweaver.jar

一、配置LTW織入器的aop.xml配置檔案
    LTW織入器在工作時,首先會查詢類路徑下META-INF /aop.xml的配置檔案,並根據配置檔案的設定進行織入的操作。

Xml程式碼  收藏程式碼
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <aspectj>
  3.     <aspects>
  4.         <!-- ①切面類 -->
  5.         <aspectname="quickstart.aspectj.Monitor"/>
  6.     </aspects>
  7.     <weaver
  8.         options="-showWeaveInfo -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler"
    >
  9.         <!-- ② 指定需要進行織入操作的目標類範圍 -->
  10.         <includewithin="quickstart.service..*"/>
  11.     </weaver>
  12. </aspectj>

二、切面織入的目標類和切面例項
Java程式碼  收藏程式碼
  1. package quickstart.service.impl;  
  2. import java.util.List;  
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.beans.factory.annotation.Qualifier;  
  5. import org.springframework.transaction.annotation.Propagation;  
  6. import org.springframework.transaction.annotation.Transactional;  
  7. import quickstart.dao.PersonDao;  
  8. import quickstart.model.Person;  
  9. import quickstart.service.PeopleService;  
  10. publicclass PeopleServiceImpl implements PeopleService{  
  11.     //通過型別(byType為預設)的自動連線可能會有多個候選,
  12.     //通過使用@Qualifier註解,使用名稱(byName)來限定
  13.     @Autowired
  14.     @Qualifier("personDao")  
  15.     private PersonDao personDao;  
  16.     @Transactional(propagation = Propagation.REQUIRED)  
  17.     publicvoid savePerson(Person person) {  
  18.         personDao.save(person);  
  19.     }  
  20.     @Transactional(readOnly = true, propagation = Propagation.REQUIRED)  
  21.     public Person findPersonById(Integer id) {  
  22.         return personDao.findById(id);  
  23.     }  
  24.     @Transactional(readOnly = true, propagation = Propagation.REQUIRED)  
  25.     public List findPersonByJPQL(String jpql){  
  26.         return personDao.findByJPQL(jpql);  
  27.     }  

Java程式碼  收藏程式碼
  1. package quickstart.aspectj;  
  2. import org.aspectj.lang.JoinPoint;  
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.Before;  
  5. import org.aspectj.lang.annotation.Pointcut;  
  6. @Aspect
  7. publicclass Monitor {  
  8.     @Pointcut("execution(* quickstart.service.impl.*.*(..))")  
  9.     publicvoid anyService(){}  
  10.     @Before("quickstart.aspectj.Monitor.anyService()")  
  11.     publicvoid log(JoinPoint joinPoint){  
  12.         System.out.println("Service Method " + joinPoint.getSignature().getName() + " Invocation!");  
  13.     }  
  14. }  

三、Spring配置檔案applicationContext.xml
Xml程式碼  收藏程式碼
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xmlns:aop="http://www.springframework.org/schema/aop"
  5.     xmlns:tx="http://www.springframework.org/schema/tx"
  6.     xsi:schemaLocation="  
  7.     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  8.     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd  
  9.     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
  10.     <!-- 需要指定factory-method="aspectOf"屬性,以便確保Spring從AspectJ獲取切面例項,而非自己建立該例項。 -->
  11.     <beanid="momitor"class="quickstart.aspectj.Monitor"factory-method="aspectOf"/>
  12.     <!-- 自動裝配註解Bean後置處理器 -->
  13.     <bean
  14.         class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
  15.     <!-- JPA註解Bean後置處理器 -->
  16.     <bean
  17.         class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
  18.     <!-- 利用Spring的實體管理器工廠來建立JPA實體管理器 -->
  19.     <beanid="entityManagerFactory"
  20.         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  21.         <propertyname="dataSource"ref="dataSource"/>
  22.         <propertyname="jpaVendorAdapter">
  23.             <bean
  24.                 class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
  25.                 <propertyname="database"value="MYSQL"/>
  26.                 <propertyname="showSql"value="true"/>
  27.                 <!-- <property name="generateDdl" value="true" /> -->
  28.             </bean>
  29.         </property>
  30.     </bean>
  31.     <beanid="dataSource"
  32.         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  33.         <propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
  34.         <propertyname="url"value="jdbc:mysql://localhost/test?useUnicode=true&amp;characterEncoding=UTF-8"/>
  35.         <propertyname="username"value="root"/>
  36.         <propertyname="password"value="root"/>
  37.     </bean>
  38.     <!-- 宣告一個Spring提供的JPA事務管理器,傳入的引數是Spring中的實體管理器工廠 -->
  39.     <beanid="transactionManager"
  40.         class="org.springframework.orm.jpa.JpaTransactionManager">
  41.         <propertyname="entityManagerFactory"ref="entityManagerFactory"/>
  42.     </bean>
  43.     <!-- 開啟Spring提供的基於註解的宣告式事務管理 -->
  44.     <tx:annotation-driventransaction-manager="transactionManager"/>
  45.     <!-- 直接使用Spring的 JpaTemplate -->
  46.     <beanid="jpaTemplate"class="org.springframework.orm.jpa.JpaTemplate">
  47.         <propertyname="entityManagerFactory"ref="entityManagerFactory"/>
  48.     </bean>
  49.     <beanid="personDao"class="quickstart.dao.impl.PersonDaoImpl"autowire="byName"/>
  50.     <beanid="peopleService"class="quickstart.service.impl.PeopleServiceImpl"/>
  51. </beans>

四、測試
Java程式碼  收藏程式碼
  1. package logcd.test;  
  2. import java.util.List;  
  3. import org.junit.BeforeClass;  
  4. import org.junit.Ignore;  
  5. import org.junit.Test;  
  6. import org.springframework.context.ApplicationContext;  
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  8. import quickstart.model.Address;  
  9. import quickstart.model.Person;  
  10. import quickstart.service.PeopleService;  
  11. publicclass JpaServiceTest {  
  12.     privatestatic ApplicationContext appContext;  
  13.     privatestatic PeopleService peopleService;  
  14.     @BeforeClass
  15.     publicstaticvoid Init(){     
  16.         appContext = new ClassPathXmlApplicationContext("applicationContext.xml");  
  17.         peopleService = (PeopleService)appContext.getBean("peopleService");  
  18.     }   
  19.     @Test
  20.     publicvoid findById(){  
  21.         Person person = peopleService.findPersonById(new Integer(2));  
  22.         System.out.println(person.getFirstName()+person.getLastName());  
  23.         //System.out.println(person.getAddress().getStreetName());
  24.     }  
  25.     @Test
  26.     publicvoid findByJPQL(){  
  27.         StringBuilder jpql = new StringBuilder();  
  28.         jpql.append(" FROM Person p JOIN FETCH p.address");  
  29.         List list = peopleService.findPersonByJPQL(jpql.toString());  
  30.         for(Object obj : list){  
  31.             Person person = (Person)obj;  
  32.             System.out.println(person.getFirstName() + person.getLastName());  
  33.             System.out.println(person.getAddress().getStreetName());  
  34.         }  
  35.     }