AOP,面向切面编程,作为OOP的一种补充,在处理一些系统共有的业务,比如日志,事务等,提供了一种比OOP更佳的解决方案。

在OOP中,控制的粒度为对象,因此,对象中也就参杂这不属于本身业务主体的一下系统共有的业务:

登陆提供了如下接口:

package me.hockey.spring.aoptest;

public interface ILogin {
String loginByname(String name);
}

例如以一个简单的硬编码的登陆为例子,在未使用AOP前纪录日志的工作都是嵌套在业务中间的,如下所示:

package me.hockey.spring.aoptest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert; public class LoginWithOutAOP implements ILogin{
private Logger logger = LoggerFactory.getLogger(Login.class);
public String loginByname(String name) {
Assert.notNull(name);
logger.info("Login by name invoke! args:" + name);
if("he".equals(name)){
logger.info("Login ok:" + name);
return "login ok";
} else {
logger.info("Login failed:" + name);
return "login failed";
}
}
}

可以看到,在没有使用AOP前,日志记录在以上的代码中占据了四行位置。其实日志记录在很多地方都会使用到,这样,无疑就将与具体业务无关的日志代码引入到了具体的业务中了,而且日志代码也影响了代码的简洁性。

AOP提供了更细粒度的控制,同样使用以上例子,使用AOP时,无须在业务中添加关于日志的代码,如下:

package me.hockey.spring.aoptest;

import org.springframework.util.Assert;

public class Login implements ILogin{
public String loginByname(String name) {
Assert.notNull(name);
if("he".equals(name)){
return "login ok";
} else {
return "login failed";
}
}
}

这样所有的代码都与本业务相关了,没有多余的代码,代码的简洁性也得到了保证。

当然,要使用AOP,还要对AOP进行相关的配置,关于AOP的一些术语,join point(连接点)、point cut(切入点)、advice(通知)、aspect(方面)、introduce(引入),就不再过多论述了。本文使用SpringAspectj来对AOP进行配置。

Spring对AOP有很好的支持,在maven中添加对Spring-aop、Spring-context和aspectj的依赖。

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.0.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.0_M5</version>
</dependency>

日志使用slf4jlog4j,同样添加两者的依赖

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.0_M5</version>
</dependency>

一个很简单的日志记录,

import org.aspectj.lang.JoinPoint;

/**
* AOP 日志接口
* @author Hockey
*
*/
public interface IAopLog {
void logBefore(JoinPoint jointPoint);
void logAfter(JoinPoint jointPoint);
void logAfterReturn(JoinPoint jointPoint,Object o);
void logAfterThrow(JoinPoint jointPoint,Throwable tr);
}

日志类的实现如下:

package me.hockey.spring.apotest.utils;

import java.util.Date;

import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class AopLogImpl implements IAopLog{ Logger logger = LoggerFactory.getLogger(AopLogImpl.class); public void logBefore(JoinPoint jointPoint) { logger.info("before "+new Date().toString()+
jointPoint.getTarget().toString()+
jointPoint.getSignature().getName()+
jointPoint.getArgs().toString());
} public void logAfter(JoinPoint jointPoint) {
logger.info("After "+new Date().toString()+
jointPoint.getTarget().toString()+
jointPoint.getSignature().getName()+
jointPoint.getArgs().toString());
} public void logAfterReturn(JoinPoint jointPoint,Object o) {
logger.info("AfterReturn "+new Date().toString()+
jointPoint.getTarget().toString()+
jointPoint.getSignature().getName()+
jointPoint.getArgs().toString()
+o.toString());
} public void logAfterThrow(JoinPoint jointPoint,Throwable tr) {
logger.info("AfterThrow "+new Date().toString()+
jointPoint.getTarget().toString()+
jointPoint.getSignature().getName()+
jointPoint.getArgs().toString()+
tr.getMessage());
} }

applicationcontext.xml的配置:

添加AOP的xsd

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx">
<bean id="login" class="me.hockey.spring.aoptest.Login"/>
<bean id="aopLog" class="me.hockey.spring.apotest.utils.AopLogImpl"/>
<aop:config>
<aop:pointcut id="loginPointCut" expression="execution(* me.hockey.spring.aoptest.Login.*(..))"/>
<aop:aspect id="loginAspect" ref="aopLog">
<aop:before method="logBefore" pointcut-ref="loginPointCut"/>
<aop:after method="logAfter" pointcut-ref="loginPointCut" />
<aop:after-returning method="logAfterReturn" returning="o" pointcut-ref="loginPointCut"/>
<aop:after-throwing method="logAfterThrow" throwing="tr" pointcut-ref="loginPointCut"/>
</aop:aspect>
</aop:config>
</beans>

测试类代码:

package me.hockey.spring.aoptest.test;

import me.hockey.spring.aoptest.ILogin;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class AopTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext/ApplicationContext.xml");
ILogin login = (ILogin) ac.getBean("login");
login.loginByname("he");
login.loginByname(null);
}
}

日志记录结果:

[INFO ] 2013-12-30 04:41:25,545(0) --> [main] org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:447): Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1950198: startup date [Mon Dec 30 04:41:25 CST 2013]; root of context hierarchy
[INFO ] 2013-12-30 04:41:25,598(53) --> [main] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:315): Loading XML bean definitions from class path resource [applicationcontext/ApplicationContext.xml]
[INFO ] 2013-12-30 04:41:25,775(230) --> [main] org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:532): Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f98d58: defining beans [login,aopLog,org.springframework.aop.config.internalAutoProxyCreator,loginPointCut,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,org.springframework.aop.aspectj.AspectJPointcutAdvisor#2,org.springframework.aop.aspectj.AspectJPointcutAdvisor#3]; root of factory hierarchy
[INFO ] 2013-12-30 04:41:26,044(499) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logBefore(AopLogImpl.java:15): before Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@1e2c9bf
[INFO ] 2013-12-30 04:41:26,044(499) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logAfter(AopLogImpl.java:22): After Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@1e2c9bf
[INFO ] 2013-12-30 04:41:26,045(500) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logAfterReturn(AopLogImpl.java:29): AfterReturn Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@1e2c9bflogin ok
[INFO ] 2013-12-30 04:41:26,045(500) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logBefore(AopLogImpl.java:15): before Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@10e9df
[INFO ] 2013-12-30 04:41:26,045(500) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logAfter(AopLogImpl.java:22): After Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@10e9df
[INFO ] 2013-12-30 04:41:26,045(500) --> [main] me.hockey.spring.apotest.utils.AopLogImpl.logAfterThrow(AopLogImpl.java:37): AfterThrow Mon Dec 30 04:41:26 CST 2013me.hockey.spring.aoptest.Login@1586cbdloginByname[Ljava.lang.Object;@10e9df[Assertion failed] - this argument is required; it must not be null

至此,一个简单的AOP记录日志的功能已经实现了,当然,只要在Spring配置文件里面配置好,日志这一个功能可以被很多地方复用。

浅谈AOP的更多相关文章

  1. 浅谈对Spring Framework的认识

    Spring Framework,作为一个应用框架,官方的介绍如下: The Spring Framework provides a comprehensive programming and con ...

  2. MVC5-11 浅谈拦截器

    Filter拦截器 Aop是MVC的主要设计方式之一,而微软也希望我们在使用MVC的时候更好的使用拦截器来进行切面编程.拦截器则是Mvc中的一大亮点与重点 AOP(面向切面)编程已经广泛应用在各个项目 ...

  3. !! 浅谈Java学习方法和后期面试技巧

    浅谈Java学习方法和后期面试技巧 昨天查看3303回复33 部落用户大酋长 下面简单列举一下大家学习java的一个系统知识点的一些介绍 一.java基础部分:java基础的时候,有些知识点是非常重要 ...

  4. 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

    谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...

  5. 1.1浅谈Spring(一个叫春的框架)

    如今各种Spring框架甚嚣尘上,但是终归还是属于spring的东西.所以在这里,个人谈一谈对spring的认识,笔者觉得掌握spring原理以及spring所涉及到的设计模式对我们具有极大的帮助.我 ...

  6. 【ASP.NET MVC系列】浅谈ASP.NET MVC运行过程

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  7. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  8. 浅谈.NET编译时注入(C#-->IL)

    原文:浅谈.NET编译时注入(C#-->IL) .NET是一门多语言平台,这是我们所众所周知的,其实现原理在于因为了MSIL(微软中间语言)的一种代码指令平台.所以.NET语言的编译就分为了两部 ...

  9. laravle6.0-IOC-DI浅谈

    1.什么是IOC,DI IOC(Inversion of Control)控制反转:ioc意味着,你将自己设计好的对象交给容器来控制,而不是传统的在你的对象内部直接控制.比如: 人 操控 手机 做一些 ...

随机推荐

  1. Qt json 数据处理

    用到的头文件 #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> json解 ...

  2. 通过挂载系统光盘搭建本地yum仓库的方法

    在CentOS系统中,我们常常会安装大量的软件,但许多软件包都存在需要依赖性,当然我们可以通过一一安装依赖包来完成安装,但对于有些软件包需要大量的依赖包,再一一安装起来会显得特别麻烦.接下来我们就来讲 ...

  3. js加密参数传给后台,后台解密base64

    前台js // base64加密开始 var keyStr = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZabcdef" + " ...

  4. GPS 气压计高度测量

    气压计测某个点的高度是不准的,因为天气.温度等原因会导致不同时刻同一地点气压不同,所以气压计测量不准.但气压计测量相对高度是很准的.GPS测相对高度不准,但测定点高度比较准.

  5. cell单选

    先上图给看看效果 cell单选逻辑就是取出上一个选中的cell 设置图片为默认图片 在取出点击的cell 设置图片为选中图片即可 废话不多说直接上代码 p.p1 { margin: 0.0px 0.0 ...

  6. eclipse各版本介绍

    记录下吧!以免以后下载时候又不知道下载那个: Eclipse IDE for Java Developers 是为java开发的 Eclipse IDE for Java EE Developers  ...

  7. Dcloud HTML5 监听蓝牙设备 调用 原生安卓实现

    最近一直搞Dcloud ,这是HTML5版本的开发,打包时候,可以打包成 apk 和ipa 分别运行在安卓和ios 机器上面, 但是这里面的资料很少,遇到问题,之后只能自己钻研总结, 现在有这么一个需 ...

  8. html内的空格占位

    写html的时候有时因为字数不够会根据字段长度添加多个空格,但是在html中添加空格是没有用的,所以使用空格的代替符号有:   不断行的空白(1个字符宽度)   半个空白(1个字符宽度)   一个空白 ...

  9. 素数的平方阶群必为Abel群

    定理  设$p$为素数,则$p^2$阶群$G$必为Abel群.

  10. 3.2 配置构建Angular应用——简单的笔记存储应用

    本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性.这个应用用到的特性有: 在JSON文件中存储笔记 展示.创建.修改和删除笔记 在笔记中使用M ...