问题:什么是AOP?

答:AOP基本概念:Aspect-Oriented Programming,面向方面编程的简称,Aspect是一种新的模块化机制。用来描写叙述分散在对象、类或方法中的横切关注点(crosscutting concern), 从关注点中分离出横切关注点是面向方面程序设计的核心所在。

分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特 定领域问题代码的调用。业务逻辑同特定领域问题的关系通过方面来封装、维护,这样原本分散在整个应用程序中的变动就能够非常好地管理起来。

个人理解:所谓的AOP就是把我们的程序的运行看成是一个方块的面包,然后切成了一片一片的吐司--这些吐司就是我们一个一个的方法。

然后在这些吐司片的前面,后面、甚至是里面来做一些特定条件下发生的特定事情。比方嵌入几个葡萄干、给前面加苹果酱、给后面加草莓酱这种事情。。优势在于你能够在自己的AOP方法中规定一个加苹果酱的理由,满足这个理由的话就能够加苹果酱,而不用在每一个方法中都特定的指出加苹果酱,加草莓酱什么的··个人理解···。

AOP的实现有非常多的方式。我这边使用Spring中自带的aop来做一些业务逻辑的实现。

在Spring中实现aop的方式有两种。各自是通过xml配置和通过注解配置。以下来介绍这两种方式。

在介绍他们之前先看一下项目的结构:

上图中ServiceAspect是我们使用注解的方式来实现AOP的类,InteceptorXML是使用XML来实现AOP的类;TestAop是測试方法;TestServiceImpl;TestService是用来被AOP的动作。(须要明白的是,AOP的动作建议都发生在service层面。

)application-context.xml是我的配置文件。

1.通过注解配置。

我注解AOP的代码例如以下:

package test.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; import test.entity.User; @Component
// 声明这是一个组件
@Aspect
// 声明这是一个切面bean
public class ServiceAspect { // 配置切入点,该方法无方法体,主要是为了同类中其它方法使用此处配置的切入点 ----见(1)
@Pointcut("execution(* test.service..*.*(..))")
public void aspect() {
} // 配置前置通知,使用在方法aspect()上注冊的切入点,同一时候接受JoinPoint切入点对象。能够没有该參数 ----见(2)
@Before("aspect()&&args(id)")
public void before(JoinPoint joinPoint, long id) {
System.out.println(id + "------------------");
System.out.println("before-->" + joinPoint);
} // 配置后置通知,使用在方法aspect()上注冊的切入点----见(3)
@After("aspect()&&args(id)")
public void after(JoinPoint joinPoint, long id) {
System.out.println(id + "after----------------------");
System.out.println("after-->" + joinPoint);
} // 配置围绕通知----见(4)
@Around("aspect()")
public Object around(JoinPoint joinPoint) {
long start = System.currentTimeMillis(); try {
Object o=((ProceedingJoinPoint) joinPoint).proceed();
User user = (User)o;
System.out.println("-----around======="+user.toString());
long end = System.currentTimeMillis();
System.out.println("around -->" + joinPoint + "\tUse time : "
+ (end - start) + " ms!");
return user;
} catch (Throwable e) {
long end = System.currentTimeMillis();
System.out.println("around __>" + joinPoint + "\tUse time : "
+ (end - start) + " ms with exception : " + e.getMessage());
return null;
} } // 配置后置返回通知,使用在方法aspect()上注冊的切入点----见(5)
@AfterReturning(pointcut = "aspect()", returning = "returnVal")
public void afterReturning(JoinPoint joinPoint, Object returnVal) {
System.out.println("afterReturning executed, return result is "
+ returnVal);
} // 配置抛出异常后通知,使用在方法aspect()上注冊的切入点----见(6)
@AfterThrowing(pointcut = "aspect()", throwing = "ex")
public void afterThrow(JoinPoint joinPoint, Exception ex) {
System.out.println("afterThrow--> " + joinPoint + "\t"
+ ex.getMessage());
}
}

非常多内容在凝视中已经有了。这里说一下几个关键的easy让人不明确的地方。

(1)@Pointcut("execution(* test.service..*.*(..))")就是我们定义的切入点,在括号中面的參数是指定了哪些方法是在考虑切入的范围内的;

* test.service..*.*(..)能够这样来解剖:

第一个* :表示被拦截的方法能够是随意的返回类型;

test.service:指定了要拦截的包。

..:这两个..表示的是被指定的拦截包test.service中全部的子包中的类的方法都要考虑到拦截的范围中;

*:表示随意的类。

.*:表示随意的方法;

(..):表示随意的方法參数;

总结起来,就是告诉我们这样一个信息:要拦截test.service中全部子包中的全部类的全部方法,这些方法的返回值能够是随意的,參数能够是随意的。

当然,我们也能够特定很多内容。可是格式不要变。比如:

@Pointcut(“execution(* test.service..*.add*(..))”)

那么所要拦截的方法就必须以add来开头了。

切入点的方法中不实现不论什么的操作,作用仅仅是提供给其它的切面来使用。

(2)

@Before("aspect()&&args(id)")中的 aspect(),指定指定切入点的方法。就是我们定义为pointCut的aspect()方法,然后args(id),我们获取了所拦截的方法的传入的參数中的id;在before方法中我们能够在切入点运行曾经来做一些操作。 当中的joinPoint是切入点的相关信息。

(3)

@After("aspect()&&args(id)")同(2)。仅仅是这是在切入点运行完毕以后来做出一些处理。

(4)

@Around("aspect()")是围绕通知,在围绕通知中我们能切入点的非常多内容进行改动;

当中通过Object o=((ProceedingJoinPoint) joinPoint).proceed();我们就能够让切入点的方法完毕,获得他的执行结果。

然后User user = (User)o;我们把它转换为User对象。假设在return user,之前我们加上user.setName("after aa");就能够改变切入点的执行结果。

这样的操作对于非常多的错误检測以及格式检測是非常实用处的。

(5)

@AfterReturning(pointcut = "aspect()", returning = "returnVal")

这里是切入点有返回结果后做的操作。通过returning的定义我们能获得切入点的返回结果;

(6)

@AfterThrowing(pointcut = "aspect()", throwing = "ex")

这里能够在切入点抛出异常后做一些工作,通过定义throwing我们能获得抛出的异常对象。

相关代码:

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="test"> <!--开启spring自己定义的包扫描,我定义的为扫描test包下全部内容-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--这里不扫描controller。在mvc中扫描,安全又可靠-->
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><!--开启凝视方式的spring aop-->
<bean id="userService" class="test.service.impl.UserService"></bean><!--注入userService-->
</beans>

UserService

package test.service.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import test.entity.User; public class UserService {
private final static Log log = LogFactory.getLog(UserService.class); public User get(long id) {
if (log.isInfoEnabled()) {
log.info("getUser method . . .");
}
User user = new User(1, "test");
return user;
} public void save(User user) {
if (log.isInfoEnabled()) {
log.info("saveUser method . . .");
}
} public boolean delete(long id) throws Exception {
if (log.isInfoEnabled()) {
log.info("delete method . . .");
throw new Exception("spring aop ThrowAdvice演示");
}
return false;
}
}

test方法

package demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import test.entity.User;
import test.service.impl.UserService; public class TestAop { public static void main(String[] args) {
ApplicationContext aContext = new ClassPathXmlApplicationContext("application-context.xml");//载入spring文件
UserService userService = (UserService) aContext.getBean("userService");//获得userservice
User user =userService.get(1L);//调用get方法。
System.out.println(user);
try {
userService.delete(1L);//调用delete方法。
} catch (Exception e) {
System.out.println("Delete user : " + e.getMessage());
}
}
}

測试结果:

2.通过XML来配置

通过xml来配置AOP,操作都在xml文件里完毕

在xml中做例如以下配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- <context:component-scan base-package="test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
<bean id="userService" class="test.service.impl.UserService"></bean> <bean id="inteceptorXML" class="test.aop.InteceptorXML"></bean>
<aop:config>
<aop:aspect id="aspectd" ref="inteceptorXML">
<aop:pointcut expression="execution(* test.service..*.*(..))" id="mypointCutMethod"/>
<aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />
</aop:aspect>
</aop:config>
</beans>

在xml中我们指定了用来作为拦截器的bean----inteceptorXML,类似的指定了切入点

<aop:aspect id="aspectd" ref="inteceptorXML">指定了拦截器为interceptorXML。

execution(* test.service..*.*(..)),并指定了id为mypointCutMethod。然后定义了

<aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />

指定了调用doAccessCheck来做before拦截,其它拦截我没有指定,这里都能够指定的。

inteceptorXml

package test.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class InteceptorXML {

	public void doAccessCheck() {
System.out.println("before advice");
} public void doWriteLog() {
System.out.println("after advice");
} public void doWriteErrorLog() {
System.out.println("Exception advice");
} public Object doAroundMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("enter around advice method."); Object obj = pjp.proceed(); System.out.println("exit around advice method."); return obj;
}
}

执行以上測试方法。得到的结果例如以下:

Spring中AOP的使用的更多相关文章

  1. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

  2. Spring中AOP简介与切面编程的使用

    Spring中AOP简介与使用 什么是AOP? Aspect Oriented Programming(AOP),多译作 "面向切面编程",也就是说,对一段程序,从侧面插入,进行操 ...

  3. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  4. Spring 中aop切面注解实现

    spring中aop的注解实现方式简单实例   上篇中我们讲到spring的xml实现,这里我们讲讲使用注解如何实现aop呢.前面已经讲过aop的简单理解了,这里就不在赘述了. 注解方式实现aop我们 ...

  5. Spring中AOP相关源码解析

    前言 在Spring中AOP是我们使用的非常频繁的一个特性.通过AOP我们可以补足一些面向对象编程中不足或难以实现的部分. AOP 前置理论 首先在学习源码之前我们需要了解关于AOP的相关概念如切点切 ...

  6. AOP 与 Spring中AOP使用(上)

    AOP简介 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP是OOP的延续 ...

  7. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  8. 浅析Spring中AOP的实现原理——动态代理

    一.前言   最近在复习Spring的相关内容,刚刚大致研究了一下Spring中,AOP的实现原理.这篇博客就来简单地聊一聊Spring的AOP是如何实现的,并通过一个简单的测试用例来验证一下.废话不 ...

  9. Spring中AOP相关的API及源码解析

    Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...

  10. Spring中AOP的模拟实现

    什么是AOP? 面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面 面向 ...

随机推荐

  1. linux php安装ODBC扩展

    进入php源码安装目录的ext/pdo_odbc $ sudo /data/apps/php/bin/phpize $ ./configure --with-php-config=/data/apps ...

  2. docker-ce快速部署

    配置yum源wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repowget -O ...

  3. phpstorm使用Database关联数据库

    1.如图选择mysql 配置数据库连接及shh 点击Test Connection,如果成功,即可点击ok连接mysql数据库 2.如图选择所有的表 3.更新数据

  4. html/css:简单网页

    html: <!DOCTYPE html> <html> <head> <meta http-equiv=“content-type” content=“te ...

  5. tomcat——大致简介和执行过程

    jsp简介 JSP: JAVA Server Page 使用JAVA语言编写的一种在服务器运行的动态页面 JSP = JAVA + HTML JSP 的执行过程 1: 翻译阶段 把JSP源文件翻译成 ...

  6. vsftpd系统用户配置详解

    1.安装yum -y install pam pam-devel db4 de4-devel db4-uitls db4-tclyum -y install vsftpd 新建vsftpd系统用户:u ...

  7. xtu summer individual 4 C - Dancing Lessons

    Dancing Lessons Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on CodeForces. ...

  8. Flask--修改默认的static文件夹的方法

    修改的flask默认的static文件夹只需要在创建Flask实例的时候,把static_folder和static_url_path参数设置为空字符串即可. app = Flask(__name__ ...

  9. gitHub网站上常见英语翻译

    为开发者而建Built for developers GitHub is a development platform inspired by the way you work.GitHub是一个受你 ...

  10. 【Kruscal最小生成树】D. Jungle Roads

    https://www.bnuoj.com/v3/contest_show.php?cid=9154#problem/D [Accepted] #include<iostream> #in ...