标签:
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、建立一个切面,监控上述类的对象的行为,给每一个步骤打印日志。
首先,定义一个借口,规范文本操作的步骤:
1 public interface handleText { 2 public String readFile(String filePath); 3 public String processContent(String Content); 4 public void writeFile(String fileContent, String FilePath); 5 }
然后,实现定义一个类实现接口的具体方法:
1 public class TextHandler implements handleText { 2 3 public String readFile(String filePath) 4 { 5 String line = ""; 6 7 StringBuffer strBuffer = new StringBuffer(); 8 try{ 9 BufferedReader bf = new BufferedReader(new FileReader(new File(filePath))); 10 while((line = bf.readLine())!=null) 11 { 12 strBuffer.append(line).append("#"); 13 System.out.println(line); 14 } 15 bf.close(); 16 }catch (FileNotFoundException e) 17 { 18 System.out.println("File not Found"); 19 return null; 20 }catch (IOException e) 21 { 22 System.out.println("IOExecption "); 23 return null; 24 } 25 System.out.println("FileContent =="+strBuffer.toString()); 26 return strBuffer.toString(); 27 } 28 29 public String processContent(String targetStr) 30 { 31 String replaceMentStr = "No Necessary"; 32 String rtnString = targetStr.replaceAll("HOT", replaceMentStr); 33 return rtnString; 34 } 35 36 public void writeFile(String fileContent, String filePath) 37 { 38 try{ 39 BufferedWriter bufWriter = new BufferedWriter(new FileWriter(filePath)); 40 41 String[] lines = fileContent.split("#"); 42 int lineCount = lines.length; 43 int i = 0; 44 while(i<lineCount) 45 { 46 bufWriter.write(lines[i]); 47 bufWriter.newLine(); 48 i++; 49 } 50 bufWriter.flush(); 51 bufWriter.close(); 52 System.out.println("Write OK "); 53 } 54 catch(IOException e) 55 { 56 // Nothing To Do 57 } 58 } 59 }
到现在,我们的主逻辑已经实现了。现在定义一个切面,在读取文本前打印日志,在将处理后的文本写入指定文件后,输出写入完毕的日志。
Spring AOP的实现方式有四种,我在实际开发中常用的是两种:AspectJ注解的方式,POJO的<AOP:Config>方式,AspectJ需要单独一篇文章介绍,这里使用POJO的方式实现。
首先,定义一个类,就是个POJO。在这个类里面实现我们需要的日志打印操作。
1 public class logForTextHandler { 2 3 static Logger logger; 4 static { 5 logger = Logger.getLogger(TextHandler.class); 6 } 7 public void befoeReadFile() 8 { 9 logger.info("Now Ready To Read Text From File"); 10 } 11 public void afterProcessContent() 12 { 13 14 logger.info("Process Is Done and the Result is +" ); 15 } 16 17 public void aroundWriteFile(ProceedingJoinPoint jointPoint) 18 { 19 logger.info("Now Write The Processed Content Into File"); 20 try { 21 jointPoint.proceed(); 22 logger.info("Sucess Writing The File "); 23 } catch (Throwable e) { 24 System.out.println("Error When Writing File"); 25 e.printStackTrace(); 26 } 27 } 28 29 }
剩下的事情就是在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的运行机制,这个东西,以后慢慢写。
标签:
原文地址:http://www.cnblogs.com/tju-gsp/p/4622021.html