第2章 Spring AOP(理论)
- 格式:ppt
- 大小:2.16 MB
- 文档页数:38


Spring学习教程(⼀):Spring中AOP基础Spring中AOP基础⼀、以⼀个例⼦引⼊1、例⼦描述:实现⼀个加减乘除的计算器,要求有⽇志,能给在程序执⾏期间追踪正在发⽣的活动。
2、代码⽰例:ArithmeticCalculator接⼝:package com.at.aop;public interface ArithmeticCalculator {int add(int i,int j);int sub(int i,int j);int mul(int i,int j);int div(int i,int j);}ArithmeticCalculator接⼝的实现类ArithmeticCalculatorLoggingImplpackage com.at.aop;public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {@Overridepublic int add(int i, int j) {System.out.println("add ⽅法输⼊参数是["+i+","+j+"]");int result = i + j;System.out.println("add ⽅法输出结果是"+result);return result;}@Overridepublic int sub(int i, int j) {System.out.println("sub ⽅法输⼊参数是["+i+","+j+"]");int result = i - j;System.out.println("sub ⽅法输出结果是"+result);return result;}@Overridepublic int mul(int i, int j) {System.out.println("mul ⽅法输⼊参数是["+i+","+j+"]");int result = i * j;System.out.println("mul ⽅法输出结果是"+result);return result;}@Overridepublic int div(int i, int j) {System.out.println("div ⽅法输⼊参数是["+i+","+j+"]");int result = i / j;System.out.println("div ⽅法输出结果是"+result);return result;}}测试函数package com.at.aop;public class TestArithmeticCalculator {public static void main(String[] args) {ArithmeticCalculator arithmeticCalculator = null;arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();int result = arithmeticCalculator.add(1, 2);System.out.println(result);result = arithmeticCalculator.div(4, 2);System.out.println(result);}}运⾏结果:add ⽅法输⼊参数是[1,2]add ⽅法输出结果是33div ⽅法输⼊参数是[4,2]div ⽅法输出结果是223、例⼦总结(1)代码混乱:越来越多的⾮业务需求(⽇志和验证等)加⼊后, 原有的业务⽅法急剧膨胀。
此前对于AOP的使用仅限于声明式事务,除此之外在实际开发中也没有遇到过与之相关的问题。
最近项目中遇到了以下几点需求,仔细思考之后,觉得采用AOP 来解决。
一方面是为了以更加灵活的方式来解决问题,另一方面是借此机会深入学习Spring AOP相关的内容。
本文是权当本人的自己AOP学习笔记,以下需求不用AOP肯定也能解决,至于是否牵强附会,仁者见仁智者见智。
1对部分函数的调用进行日志记录,用于观察特定问题在运行过程中的函数调用情况2监控部分重要函数,若抛出指定的异常,需要以短信或邮件方式通知相关人员3金控部分重要函数的执行时间事实上,以上需求没有AOP也能搞定,只是在实现过程中比较郁闷摆了。
4需要打印日志的函数分散在各个包中,只能找到所有的函数体,手动添加日志。
然而这些日志都是临时的,待问题解决之后应该需要清除打印日志的代码,只能再次手动清除^_^!5类似1的情况,需要捕获异常的地方太多,如果手动添加时想到很可能明天又要手动清除,只能再汗。
OK,该需求相对比较固定,属于长期监控的范畴,并不需求临时添加后再清除。
然而,客户某天要求,把其中20%的异常改为短信提醒,剩下的80%改用邮件提醒。
改之,两天后,客户抱怨短信太多,全部改成邮件提醒...6该需求通常用于监控某些函数的执行时间,用以判断系统执行慢的瓶颈所在。
瓶颈被解决之后,烦恼同情况1终于下定决心,采用AOP来解决!代码如下:切面类TestAspectJava代码7package com.spring.aop;8/**9* 切面10*11*/12public class TestAspect {1314public void doAfter(JoinPoint jp) {15System.out.println("log Ending method: "16+ jp.getTarget().getClass().getName() + "."17+ jp.getSignature().getName());18}1920public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 21long time = System.currentTimeMillis();22Object retVal = pjp.proceed();23time = System.currentTimeMillis() - time;24System.out.println("process time: " + time + " ms");25return retVal;26}2728public void doBefore(JoinPoint jp) {29System.out.println("log Begining method: "30+ jp.getTarget().getClass().getName() + "."31+ jp.getSignature().getName());32}3334public void doThrowing(JoinPoint jp, Throwable ex) {35System.out.println("method " + jp.getTarget().getClass().getName() 36+ "." + jp.getSignature().getName() + " throw exception"); 37System.out.println(ex.getMessage());38}3940private void sendEx(String ex) {41//TODO 发送短信或邮件提醒42}43}Java代码44package com.spring.service;45/**46* 接口A47*/48public interface AService {4950public void fooA(String _msg);5152public void barA();53}Java代码54package com.spring.service;55/**56*接口A的实现类57*/58public class AServiceImpl implements AService {5960public void barA() {61System.out.println("AServiceImpl.barA()");62}6364public void fooA(String _msg) {65System.out.println("AServiceImpl.fooA(msg:"+_msg+")");66}67}Java代码68package com.spring.service;6970/**71* Service类B72*/73public class BServiceImpl {7475public void barB(String _msg, int _type) {76System.out.println("BServiceImpl.barB(msg:"+_msg+" type:"+_type+")");77if(_type == 1)78throw new IllegalArgumentException("测试异常");79}8081public void fooB() {82System.out.println("BServiceImpl.fooB()");83}8485}ApplicationContextJava代码86<?xml version="1.0" encoding="UTF-8"?>87<beans xmlns="/schema/beans"88xmlns:xsi="/2001/XMLSchema-instance"89xmlns:aop="/schema/aop"90xsi:schemaLocation="91/schema/beans92/schema/beans/spring-beans-2.0.xsd93/schema/aop94/schema/aop/spring-aop-2.5.xsd"95default-autowire="autodetect">96<aop:config>97<aop:aspect id="TestAspect" ref="aspectBean">98<!--配置com.spring.service包下所有类或接口的所有方法-->99<aop:pointcut id="businessService"100expression="execution(* com.spring.service.*.*(..))" />101<aop:before pointcut-ref="businessService" method="doBefore"/> 102<aop:after pointcut-ref="businessService" method="doAfter"/>103<aop:around pointcut-ref="businessService" method="doAround"/> 104<aop:after-throwing pointcut-ref="businessService"method="doThrowing" throwing="ex"/>105</aop:aspect>106</aop:config>107108<bean id="aspectBean"class="com.spring.aop.TestAspect" />109<bean id="aService"class="com.spring.service.AServiceImpl"></bean>110<bean id="bService"class="com.spring.service.BServiceImpl"></bean>111112</beans>测试类AOPTestJava代码113public class AOPTest extends AbstractDependencyInjectionSpringContextTests { 114115private AService aService;116117private BServiceImpl bService;118119protected String[] getConfigLocations() {120String[] configs = new String[] { "/applicationContext.xml"}; 121return configs;122}123124125/**126* 测试正常调用127*/128public void testCall()129{130System.out.println("SpringTest JUnit test");131aService.fooA("JUnit test fooA");132aService.barA();133bService.fooB();134bService.barB("JUnit test barB",0);135}136137/**138* 测试After-Throwing139*/140public void testThrow()141{142try {143bService.barB("JUnit call barB",1);144} catch (IllegalArgumentException e) {145146}147}148149public void setAService(AService service) {150aService = service;151}152153public void setBService(BServiceImpl service) {154bService = service;155}156}运行结果如下:Java代码157log Begining method: com.spring.service.AServiceImpl.fooA158AServiceImpl.fooA(msg:JUnit test fooA)159log Ending method: com.spring.service.AServiceImpl.fooA160process time: 0 ms161log Begining method: com.spring.service.AServiceImpl.barA162AServiceImpl.barA()163log Ending method: com.spring.service.AServiceImpl.barA164process time: 0 ms165log Begining method: com.spring.service.BServiceImpl.fooB166BServiceImpl.fooB()167log Ending method: com.spring.service.BServiceImpl.fooB168process time: 0 ms169log Begining method: com.spring.service.BServiceImpl.barB170BServiceImpl.barB(msg:JUnit test barB type:0)171log Ending method: com.spring.service.BServiceImpl.barB172process time: 0 ms173174log Begining method: com.spring.service.BServiceImpl.barB175BServiceImpl.barB(msg:JUnit call barB type:1)176log Ending method: com.spring.service.BServiceImpl.barB177method com.spring.service.BServiceImpl.barB throw exception178测试异常《Spring参考手册》中定义了以下几个AOP的重要概念,结合以上代码分析如下:∙切面(Aspect):官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”,在本例中,“切面”就是类TestAspect所关注的具体行为,例如,AServiceImpl.barA()的调用就是切面TestAspect所关注的行为之一。
SpringAOP⽰例与实现原理总结——传统springaop、基于切⾯注⼊、基于@Asp。
⼀、代码实践1)经典的Spring Aop经典的spring aop,是基于动态代理技术的。
实现⽅式上,最常⽤的是实现MethodInterceptor接⼝来提供环绕通知,创建若⼲代理,然后使⽤ProxyBeanFactory配置⼯⼚bean,⽣成拦截器链,完成拦截。
⽰例如下:1package demo.spring;23import org.aopalliance.intercept.MethodInterceptor;4import org.aopalliance.intercept.MethodInvocation;5import org.junit.Test;6import org.junit.runner.RunWith;7import org.springframework.beans.factory.annotation.Autowired;8import org.springframework.test.context.ContextConfiguration;9import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;1011 @RunWith(SpringJUnit4ClassRunner.class)12 @ContextConfiguration("classpath:spring-config.xml")13public class TraditionalSpringAopDemo {14 @Autowired15private Service proxy;1617 @Test18public void test() {19 proxy.execute("hello world!");20 }21 }2223interface Service {24void execute(String str);25 }2627class ServiceImpl implements Service {28 @Override29public void execute(String str) {30 System.out.println("execute invoke: " + str);31 }32 }3334class Interceptor1 implements MethodInterceptor {35 @Override36public Object invoke(MethodInvocation methodInvocation) throws Throwable {37 System.out.println("interceptor1,before invoke");38 Object ret = methodInvocation.proceed();39 System.out.println("interceptor1,after invoke");40return ret;41 }42 }4344class Interceptor2 implements MethodInterceptor {45 @Override46public Object invoke(MethodInvocation methodInvocation) throws Throwable {47 System.out.println("interceptor2,before invoke");48 Object ret = methodInvocation.proceed();49 System.out.println("interceptor2,after invoke");50return ret;51 }52 }xml⽂件配置:1<?xml version="1.0" encoding="UTF-8"?>2<beans xmlns="/schema/beans"3 xmlns:xsi="/2001/XMLSchema-instance"4 xmlns:context="/schema/context"5 xmlns:aop="/schema/aop"6 xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd /schema/context /schema/context/sprin 78<context:component-scan base-package="demo.spring"/>910<bean class="demo.spring.ServiceImpl" id="service"></bean>11<bean class="demo.spring.Interceptor1" id="interceptor1"></bean>12<bean class="demo.spring.Interceptor2" id="interceptor2"></bean>13<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxy">14<property name="target" ref="service"/>15<property name="interceptorNames">16<list>17<value>interceptor1</value>18<value>interceptor2</value>19</list>20</property>21</bean>22</beans>结果:interceptor1,before invokeinterceptor2,before invokeexecute invoke: hello world!interceptor2,after invokeinterceptor1,after invoke可以看到拦截链的执⾏过程与拦截器顺序的关系。