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. Linux安装mariadb二进制版本

    上一篇说了mariadb编译安装过程,但在生产环境中一般使用发布好的二进制版本,由于安装过程和之前一样,不再详细叙述,只是简单概括一下安装过程: 1. 下载 地址为:https://downloads ...

  2. javascript的一些知识

    一.Js的this,{},[] this是Javascript语言的一个关键字,随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this指的是调用的函数自己. { } 大括号 ...

  3. CSS垂直居中

    一.单行文本垂直居中: 设置其文本的行高line-height与其父容器高度相等即可.如 <style> .test{ background-color: grey; line-heigh ...

  4. Node的express框架安装

    第一步:在cmd命令行下执行npm install -g express,安装全局的express. 第二步:在命令行中输入express,如果出现express不是内部命令时, 输入npm inst ...

  5. OOP的四个魔术方法

    1 __autoload()自动包含类文件 通常会把类的定义单独写到一个文件里,要在另外的文件调用时需要引用require,但类的定义文件会很多就会造成一下问题 //1 如果包含多个类文件,需要一一引 ...

  6. mysql 有报错  ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists

    sh-4.1# /etc/init.d/mysqld status ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql ...

  7. 同个项目写webservice引用EF出现的问题

    错误1: 定的架构无效.错误: DataModel.ssdl(2,2) : 错误 0152: 未找到具有固定名称“System.Data.SqlClient”的 ADO.NET 提供程序的实体框架提供 ...

  8. ubuntu 14.04下spark简易安装

    java安装 首先需要上oracle的网站下载 在lib目录下建立一个jvm文件夹 sudo mkdir /usr/lib/jvm 然后解压文件到这个文件夹 sudo tar zxvf jdk-8u4 ...

  9. CentOS Linux服务器安全设置

    转自:http://www.osyunwei.com/archives/754.html 引言: 我们必须明白:最小的权限+最少的服务=最大的安全 所以,无论是配置任何服务器,我们都必须把不用的服务关 ...

  10. mysql导出excel文件的几种方法

    方法一 用mysql的命令和shell select * into outfile './bestlovesky.xls' from bestlovesky where 1 order by id d ...