您的位置:首页 > 编程语言 > Java开发

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、建立一个切面,监控上述类的对象的行为,给每一个步骤打印日志。

首先,定义一个借口,规范文本操作的步骤:

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的运行机制,这个东西,以后慢慢写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: