本文源碼:GitHub·點這裏 || GitEE·點這裏git
AOP全稱:Aspect Oriented Programming,面向切面編程。經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。核心做用:能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的複用性和開發效率。AOP提供了取代繼承和委託的一種新的方案,並且使用起來更加簡潔清晰,是軟件開發中的一個熱點理念。github
(1)、通知類型:Advicespring
前置通知[Before]:目標方法被調用以前; 返回通知[After-returning]:目標方法執行成功以後; 異常通知[After-throwing]:在目標方法拋出異常以後; 後置通知[After]:目標方法完成以後; 環繞通知[Around]:在目標方法執行先後環繞通知;
(2)、鏈接點:JoinPointexpress
程序執行的某一個特定位置,如類初始先後,方法的運行先後。編程
(3)、切點:Pointcutspring-mvc
鏈接點是指那些在指定策略下可能被攔截到的方法。mvc
(4)、切面:Aspect框架
切面由切點和通知的結合。ide
(5)、引入:Introduction函數
特殊的加強,爲類添加一些屬性和方法。
(6)、織入:Weaving
將加強添加到目標類的具體鏈接點上的過程。編譯期織入,這要求使用特殊編譯器;類裝載期織入,這要求使用特殊的類加載器;動態代理織入,在運行期爲目標類添加加強生成子類的方式,Spring採用的是動態代理織入,而AspectJ採用編譯期織入和類裝載期織入。
(7)、代理:Proxy
類被AOP織入後生成一個結果類,它是融合了原類和加強邏輯的代理類。
案例基於以下類進行:
public class Book { private String bookName ; private String author ; } public interface BookService { void addBook (Book book) ; } public class BookServiceImpl implements BookService { @Override public void addBook(Book book) { System.out.println(book.getBookName()); System.out.println(book.getAuthor()); } }
public class BookAopProxyFactory { public static BookService createService() { // 目標類 final BookService bookService = new BookServiceImpl() ; // 切面類 final BookAspect bookAspect = new BookAspect(); /* * 代理類:將目標類(切入點)和 切面類(通知) 結合 */ BookService proxyBookService = (BookService) Proxy.newProxyInstance( BookAopProxyFactory.class.getClassLoader(), bookService.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前執行 bookAspect.before(); // 執行目標類的方法 Object obj = method.invoke(bookService, args); // 後執行 bookAspect.after(); return obj; } }); return proxyBookService ; } }
採用字節碼加強框架cglib,在運行時建立目標類的子類,從而對目標類進行加強。
public class BookAopCgLibFactory { public static BookService createService() { // 目標類 final BookService bookService = new BookServiceImpl() ; // 切面類 final BookAspect bookAspect = new BookAspect(); // 核心代理類 Enhancer enhancer = new Enhancer(); // 肯定父類 enhancer.setSuperclass(bookService.getClass()); // 設置回調函數 enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { bookAspect.before(); Object obj = method.invoke(bookService, args); bookAspect.after(); return obj; } }); BookServiceImpl proxyService = (BookServiceImpl) enhancer.create(); return proxyService ; } }
spring 建立代理對象,從spring容器中手動的獲取代理對象。
<!-- 建立目標類 --> <bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" /> <!-- 建立切面類 --> <bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" /> <!-- 建立代理類 --> <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.spring.mvc.service.BookService" /> <property name="target" ref="bookService" /> <property name="interceptorNames" value="myAspect" /> </bean>
public class BookAopSpringHalf implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Method Before ..."); Object obj = methodInvocation.proceed(); System.out.println("Method After ..."); return obj; } }
從spring容器得到目標類,若是配置Aop,spring將自動生成代理。
<!-- 建立目標類 --> <bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" /> <!-- 建立切面類 --> <bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" /> <!-- AOP編程配置 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.spring.mvc.service.*.*(..))" id="myPointCut"/> <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/> </aop:config>
@Test public void test1 (){ BookService bookService = BookAopProxyFactory.createService() ; Book book = new Book() ; book.setBookName("Spring實戰"); book.setAuthor("Craig Walls"); bookService.addBook(book); } @Test public void test2 (){ BookService bookService = BookAopCgLibFactory.createService() ; Book book = new Book() ; book.setBookName("MySQL"); book.setAuthor("Baron"); bookService.addBook(book); } @Test public void test3 (){ String xmlPath = "spring-aop-half.xml"; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) context.getBean("proxyFactory"); Book book = new Book() ; book.setBookName("紅樓夢"); book.setAuthor("曹雪芹"); bookService.addBook(book); } @Test public void test4 (){ String xmlPath = "spring-aop-all.xml"; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) context.getBean("bookService"); Book book = new Book() ; book.setBookName("西遊記"); book.setAuthor("吳承恩"); bookService.addBook(book); }
AspectJ是一個基於Java語言的AOP框架,Spring2.0之後新增了對AspectJ切點表達式支持,經過JDK5註解技術,容許直接在類中定義切面,新版本Spring框架,推薦使用AspectJ方式來開發AOP編程。
public class BookAopAspectJ { public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知:" + joinPoint.getSignature().getName()); } public void myAfterReturning(JoinPoint joinPoint,Object ret){ System.out.println("後置通知:" + joinPoint.getSignature().getName() + " , -->" + ret); } public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("環繞通知前"); Object obj = joinPoint.proceed(); System.out.println("環繞通知先後"); return obj; } public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("拋出異常通知 : " + e.getMessage()); } public void myAfter(JoinPoint joinPoint){ System.out.println("最終通知"); } }
<!-- 建立目標類 --> <bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" /> <!-- 建立切面類 --> <bean id="myAspect" class="com.spring.mvc.config.BookAopAspectJ" /> <!-- 配置AOP編程 --> <aop:config> <aop:aspect ref="myAspect"> <aop:pointcut expression="execution(* com.spring.mvc.service.impl.BookServiceImpl.*(..))" id="myPointCut"/> <!-- 前置通知--> <aop:before method="myBefore" pointcut-ref="myPointCut"/> <!-- 後置通知 --> <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" /> <!-- 環繞通知 --> <aop:around method="myAround" pointcut-ref="myPointCut"/> <!-- 拋出異常 --> <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/> <!-- 最終通知 --> <aop:after method="myAfter" pointcut-ref="myPointCut"/> </aop:aspect> </aop:config>
@Test public void test1 (){ String xmlPath = "spring-aop-aspectj-01.xml"; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) context.getBean("bookService"); Book book = new Book() ; book.setBookName("三國演義"); book.setAuthor("羅貫中"); bookService.addBook(book); }
<!-- 開啓類註解的掃描 --> <context:component-scan base-package="com.spring.mvc.service.impl" /> <!-- 肯定AOP註解生效 --> <aop:aspectj-autoproxy /> <!-- 聲明切面 --> <bean id="myAspect" class="com.spring.mvc.config.AuthorAopAspectJ" /> <aop:config> <aop:aspect ref="myAspect" /> </aop:config>
@Component @Aspect public class AuthorAopAspectJ { @Pointcut("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))") private void myPointCut(){ } @Before("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知:" + joinPoint.getSignature().getName()); } @AfterReturning(value="myPointCut()" ,returning="ret") public void myAfterReturning(JoinPoint joinPoint,Object ret){ System.out.println("後置通知:" + joinPoint.getSignature().getName() + " , -->" + ret); } @Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("環繞通知前"); Object obj = joinPoint.proceed(); System.out.println("環繞通知先後"); return obj; } @AfterThrowing( value="execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))", throwing="e") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("拋出異常通知 : " + e.getMessage()); } @After("myPointCut()") public void myAfter(JoinPoint joinPoint){ System.out.println("最終通知"); } }
@Test public void test2 (){ String xmlPath = "spring-aop-aspectj-02.xml"; ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath); AuthorService authorService = (AuthorService) context.getBean("authorService"); System.out.println("做者:"+authorService.getAuthor()); }
GitHub·地址 https://github.com/cicadasmile/spring-mvc-parent GitEE·地址 https://gitee.com/cicadasmile/spring-mvc-parent