Spring AOP
2015-07-05 13:53
543 查看
1、Spring AOP的一些概念
IOC和AOP是Spring的两大核心,IOC(有的人也称其为DI)在Spring中是无处不在的。AOP在实际开发中貌似用的比较少,不少的博客说AOP可以用于日志打印、时间统计、运行监控等等。。但是在我遇到的项目中,日志还真不是用AOP来做的,基本都是强侵入性的。虽然AOP实际用的不多,但是还是需要学习的,因为码农的优良品质之一就是:永不停顿学习的脚步,无论快慢,都要保证自己在不断的前进。
AOP(Aspect Oriented Programming)涉及的概念,随便Google一下就有很多,不过还是总结下,以后忘记了还能来看看。
A. Aspect(切面)
AOP当然优先要有个A,就是Aspect(切面)。官方给出的解释是“一个关注点的模块化,这个关注点可能会横切多个对象”。切面就是监控的类所关注的行为。比如定义一个类 Monitor为切面,对象Car有行为Run()和stop()。那么Monitor就是关注点的模块化,被横切的对象就是Car,关注点关注的行为就是Car的Run()和Stop()。
B. JointPoint (连接点)
连接点就是“程序执行过程中的某一行为”。比如car.Run()这个方法执行了,或者执行过程中抛出了异常,或者执行后返回了一个值,这三种行为都是叫做连接点。这个“点”不仅仅是点,而是一种行为的发生。
C.Advice (通知)
Advice就是“切面对于某个连接点所产生的动作”。这个就更抽象了,啥叫通知呢?意思就是说当切面检测到连接点出现后,切面就得到一个通知。接着上面的例子:Monitor发现对象Car执行的函数Run(),那么Monitor就会得到一个通知,说这个Run行为发生了。个人觉得这个概念比较虚。
D.Pointcut(切点)
现在有了监视的类(切面),知道了被监视对象的动作(连接点),还能收到行为发生的通知(Advice),剩下的就是监控类该关注那些动作,切面知道Car 在Run()了,Run() 方法就是需要关注的切点。
E.Target (目标)
说了一通,忘了Car的角色了,Car就是目标。官方说法“被一个或者多个切面所通知的对象”。
F.Advice通知
刚才说了一个概念:Advice。这个通知的类型有很多,什么时候产生这个通知呢?函数执行前?执行后?返回后?抛出异常后?都可以。Spring AOP定义了很多通知的类型。
前置通知:
在函数执行前需要执行的步骤。比如Car.Run()执行前,需要检查安全带有没有扣好。那么ConfirmTheSeatBelt()就是前置通知。
后通知:
在函数执行后需要执行的步骤,比如Car.Run()执行后,车的里程表开始计算。此时milesCount()就是后置通知,注意:后置通知是只要这个函数执行过,它就会执行,即使这 个函数抛出异常了也会执行,那么问题来了,抛出异常了怎么办呢?好问题。。
抛出异常后通知:
函数执行过程中出现了异常,比如做除法,除了一个0,那么这是个异常,出了异常了,就会触发“抛出异常后通知”,针对异常就可以做点什么了。那要是执行完,没有异常,需 要有返回值呢?
返回后通知:
在函数执行完,返回了值,需要做处理。这个时候就需要对返回值做处理了。就是返回后通知要做的。
好了,现在各种情况都考虑了,不过觉得比较麻烦。想在函数的执行前后都进行处理怎么办呢?环绕通知。
这么多概念怎么玩起来呢?看栗子。。
二、Spring AOP 示例
这个例子中,要做这样一件事:
1、将文本里的内容读出来,将文本中所有的“HOT”子串都替换为 “Not Necessary”,然后将更改后的内容
写到新的文件中。
2、建立一个切面,监控上述类的对象的行为,给每一个步骤打印日志。
首先,定义一个借口,规范文本操作的步骤:
然后,实现定义一个类实现接口的具体方法:
到现在,我们的主逻辑已经实现了。现在定义一个切面,在读取文本前打印日志,在将处理后的文本写入指定文件后,输出写入完毕的日志。
Spring AOP的实现方式有四种,我在实际开发中常用的是两种:AspectJ注解的方式,POJO的<AOP:Config>方式,AspectJ需要单独一篇文章介绍,这里使用POJO的方式实现。
首先,定义一个类,就是个POJO。在这个类里面实现我们需要的日志打印操作。
剩下的事情就是在XML文件中进行配置了:
写个测试类:
这样就OK了。
这里面用到了 Log4j,把log4j的配置文件也附上:
还有pom.xml文件中的依赖。
AOP,玩起来就这么简单,复杂的永远是:在合适的场景中灵活的应用,而不是技术本身。
更复杂的是知道AOP的运行机制,这个东西,以后慢慢写。
IOC和AOP是Spring的两大核心,IOC(有的人也称其为DI)在Spring中是无处不在的。AOP在实际开发中貌似用的比较少,不少的博客说AOP可以用于日志打印、时间统计、运行监控等等。。但是在我遇到的项目中,日志还真不是用AOP来做的,基本都是强侵入性的。虽然AOP实际用的不多,但是还是需要学习的,因为码农的优良品质之一就是:永不停顿学习的脚步,无论快慢,都要保证自己在不断的前进。
AOP(Aspect Oriented Programming)涉及的概念,随便Google一下就有很多,不过还是总结下,以后忘记了还能来看看。
A. Aspect(切面)
AOP当然优先要有个A,就是Aspect(切面)。官方给出的解释是“一个关注点的模块化,这个关注点可能会横切多个对象”。切面就是监控的类所关注的行为。比如定义一个类 Monitor为切面,对象Car有行为Run()和stop()。那么Monitor就是关注点的模块化,被横切的对象就是Car,关注点关注的行为就是Car的Run()和Stop()。
B. JointPoint (连接点)
连接点就是“程序执行过程中的某一行为”。比如car.Run()这个方法执行了,或者执行过程中抛出了异常,或者执行后返回了一个值,这三种行为都是叫做连接点。这个“点”不仅仅是点,而是一种行为的发生。
C.Advice (通知)
Advice就是“切面对于某个连接点所产生的动作”。这个就更抽象了,啥叫通知呢?意思就是说当切面检测到连接点出现后,切面就得到一个通知。接着上面的例子:Monitor发现对象Car执行的函数Run(),那么Monitor就会得到一个通知,说这个Run行为发生了。个人觉得这个概念比较虚。
D.Pointcut(切点)
现在有了监视的类(切面),知道了被监视对象的动作(连接点),还能收到行为发生的通知(Advice),剩下的就是监控类该关注那些动作,切面知道Car 在Run()了,Run() 方法就是需要关注的切点。
E.Target (目标)
说了一通,忘了Car的角色了,Car就是目标。官方说法“被一个或者多个切面所通知的对象”。
F.Advice通知
刚才说了一个概念:Advice。这个通知的类型有很多,什么时候产生这个通知呢?函数执行前?执行后?返回后?抛出异常后?都可以。Spring AOP定义了很多通知的类型。
前置通知:
在函数执行前需要执行的步骤。比如Car.Run()执行前,需要检查安全带有没有扣好。那么ConfirmTheSeatBelt()就是前置通知。
后通知:
在函数执行后需要执行的步骤,比如Car.Run()执行后,车的里程表开始计算。此时milesCount()就是后置通知,注意:后置通知是只要这个函数执行过,它就会执行,即使这 个函数抛出异常了也会执行,那么问题来了,抛出异常了怎么办呢?好问题。。
抛出异常后通知:
函数执行过程中出现了异常,比如做除法,除了一个0,那么这是个异常,出了异常了,就会触发“抛出异常后通知”,针对异常就可以做点什么了。那要是执行完,没有异常,需 要有返回值呢?
返回后通知:
在函数执行完,返回了值,需要做处理。这个时候就需要对返回值做处理了。就是返回后通知要做的。
好了,现在各种情况都考虑了,不过觉得比较麻烦。想在函数的执行前后都进行处理怎么办呢?环绕通知。
这么多概念怎么玩起来呢?看栗子。。
二、Spring AOP 示例
这个例子中,要做这样一件事:
1、将文本里的内容读出来,将文本中所有的“HOT”子串都替换为 “Not Necessary”,然后将更改后的内容
写到新的文件中。
2、建立一个切面,监控上述类的对象的行为,给每一个步骤打印日志。
首先,定义一个借口,规范文本操作的步骤:
public interface handleText { public String readFile(String filePath); public String processContent(String Content); public void writeFile(String fileContent, String FilePath); }
然后,实现定义一个类实现接口的具体方法:
public class TextHandler implements handleText { public String readFile(String filePath) { String line = ""; StringBuffer strBuffer = new StringBuffer(); try{ BufferedReader bf = new BufferedReader(new FileReader(new File(filePath))); while((line = bf.readLine())!=null) { strBuffer.append(line).append("#"); System.out.println(line); } bf.close(); }catch (FileNotFoundException e) { System.out.println("File not Found"); return null; }catch (IOException e) { System.out.println("IOExecption "); return null; } System.out.println("FileContent =="+strBuffer.toString()); return strBuffer.toString(); } public String processContent(String targetStr) { String replaceMentStr = "No Necessary"; String rtnString = targetStr.replaceAll("HOT", replaceMentStr); return rtnString; } public void writeFile(String fileContent, String filePath) { try{ BufferedWriter bufWriter = new BufferedWriter(new FileWriter(filePath)); String[] lines = fileContent.split("#"); int lineCount = lines.length; int i = 0; while(i<lineCount) { bufWriter.write(lines[i]); bufWriter.newLine(); i++; } bufWriter.flush(); bufWriter.close(); System.out.println("Write OK "); } catch(IOException e) { // Nothing To Do } } }
到现在,我们的主逻辑已经实现了。现在定义一个切面,在读取文本前打印日志,在将处理后的文本写入指定文件后,输出写入完毕的日志。
Spring AOP的实现方式有四种,我在实际开发中常用的是两种:AspectJ注解的方式,POJO的<AOP:Config>方式,AspectJ需要单独一篇文章介绍,这里使用POJO的方式实现。
首先,定义一个类,就是个POJO。在这个类里面实现我们需要的日志打印操作。
public class logForTextHandler { static Logger logger; static { logger = Logger.getLogger(TextHandler.class); } public void befoeReadFile() { logger.info("Now Ready To Read Text From File"); } public void afterProcessContent() { logger.info("Process Is Done and the Result is +" ); } public void aroundWriteFile(ProceedingJoinPoint jointPoint) { logger.info("Now Write The Processed Content Into File"); try { jointPoint.proceed(); logger.info("Sucess Writing The File "); } catch (Throwable e) { System.out.println("Error When Writing File"); e.printStackTrace(); } } }
剩下的事情就是在XML文件中进行配置了:
<bean id = "logMonitor" class = " com.springAOP.FocusOnDIAOP.ForBlog.Aspect.logForTextHandler" /> <bean id = "handleFile" class = " com.springAOP.FocusOnDIAOP.ForBlog.TextHandler" /> <!-- 为博客的代码添加切面 --> <aop:config> <aop:aspect ref = "logMonitor" > <aop:pointcut id = "before-handle" expression ="execution (* com.springAOP.FocusOnDIAOP.ForBlog.TextHandler.readFile(..))" /> <aop:before pointcut-ref = "before-handle" method = "befoeReadFile" /> </aop:aspect> </aop:config> <aop:config> <aop:aspect ref = "logMonitor" > <aop:pointcut id = "around-handle" expression ="execution (* com.springAOP.FocusOnDIAOP.ForBlog.TextHandler.writeFile(..))" /> <aop:around pointcut-ref = "around-handle" method = "aroundWriteFile" /> </aop:aspect> </aop:config>
写个测试类:
public class TestCase { public static void main(String[] args) { String pathFrom = "C:/Users/shaoping.gsp/Desktop/fileForm.txt"; String pathTo = "C:/Users/shaoping.gsp/Desktop/fileTo.txt"; ApplicationContext appCtx = new ClassPathXmlApplicationContext("beans.xml"); handleText handler = (handleText) appCtx.getBean("handleFile"); String targetStr = handler.readFile(pathFrom); String fileContent = handler.processContent(targetStr); handler.writeFile(fileContent, pathTo); } }
这样就OK了。
这里面用到了 Log4j,把log4j的配置文件也附上:
# Configuration For Root Logger : Console FileLog log4j.rootLogger=info, ServerDailyRollingFile, stdout #Configuration For File Log log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd log4j.appender.ServerDailyRollingFile.File=C:/Users/shaoping.gsp/Desktop/RunTime.log log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d - %m%n log4j.appender.ServerDailyRollingFile.Append=true #ConFiguration For Console Output log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.app
还有pom.xml文件中的依赖。
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.12</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version> 1.2.9</version> </dependency> </dependencies>
AOP,玩起来就这么简单,复杂的永远是:在合适的场景中灵活的应用,而不是技术本身。
更复杂的是知道AOP的运行机制,这个东西,以后慢慢写。
相关文章推荐
- MyEclipse安装插件的几种方法
- maven myeclipse搭建
- spring3使用task:annotation-driven开始定时
- Why am I getting an Unreachable Statement error in Java?
- 在MyEclipse中统计项目行数
- Spring Resource接口
- JAVA实验第一天
- 在MyEclipse中统计项目行数
- 《java课程设计》之猜猜看游戏(一)
- java里面包的重要性-管理类文件
- Eclipse快捷键 10个最有用的快捷键
- Java类编译后Class文件概述(下)
- java反射:使用asm 获取方法的参数名
- Java基础(六)
- Java-this
- Java-构造函数
- Java-封装基础
- Java环境配置_JDK安装及配置环境变量
- Java-匿名对象
- JAVA实验第四天