Spring入门(9)-AOP初探

0. 目录

  1. 什么是面向切面编程
  2. AOP常见术语
  3. AOP实例
  4. 参考资料

1. 什么是面向切面编程

Aspect Oriented Programming(AOP),即面向切面编程。AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。最常见的就是日志记录。举个例子,我们现在提供一个服务查询学生信息服务,但是我们希望记录有谁进行了这个查询。如果按照传统的OOP的实现的话,那我们实现了一个查询学生信息的服务接口(StudentInfoService)和其实现类(StudentInfoServiceImpl.java),同时为了要进行记录的话,那我们在实现类(StudentInfoServiceImpl.java)中要添加其实现记录的过程。这样的话,假如我们要实现的服务有多个呢?那就要在每个实现的类都添加这些记录过程。这样做的话就会有点繁琐,而且每个实现类都与记录服务日志的行为紧耦合,违反了面向对象的规则。那么怎样才能把记录服务的行为与业务处理过程中分离出来呢?看起来好像就是查询学生的服务自己在进行,但却是背后日志记录对这些行为进行记录,并且查询学生的服务不知道存在这些记录过程,这就是我们要讨论AOP的目的所在。AOP的编程,好像就是把我们在某个方面的功能提出来与一批对象进行隔离,这样与一批对象之间降低了耦合性,可以就某个功能进行编程。



AOP不是Spring特有的,比如AspectJ也是AOP的实现。

2. AOP常见术语

1.通知(Advice):

通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。

Spring切面可以应用5种类型的通知。

  • Before:在方法调用前调用通知
  • After:在方法调用后调用通知
  • After-returning:在方法成功执行之后调用通知
  • After-throwing:方法抛出异常后调用通知
  • Around:在方法调用之前和调用之后执行自定义行为

2.连接点(Joinpoint):

程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。

3.切入点(Pointcut)

通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定。

4.切面(Aspect)

通知和切入点共同组成了切面:时间、地点和要发生的“故事”

5.引入(Introduction)

引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)

6.目标(Target)

即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)

7.代理(proxy)

应用通知的对象,详细内容参见设计模式里面的代理模式

8.织入(Weaving)

把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器

(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码

(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术

3. AOP实例

1. 先看接口定义

package com.chzhao.spring.aoptest;

public interface IBaseBusiness {

    /**
* 用作代理的切入点方法
*
* @param obj
* @return
*/
public String delete(String obj); /**
* 这方法不被切面切
*
* @param obj
* @return
*/
public String add(String obj); /**
* 这方法切不切呢?可以设置
*
* @param obj
* @return
*/
public String modify(String obj); }

2. 接口实现

package com.chzhao.spring.aoptest;

public class BaseBusiness implements IBaseBusiness{

	/**
* 切入点
*/
public String delete(String obj) {
System.out.println("==========调用切入点:" + obj + "说:你敢删除我!===========\n");
return obj + ":瞄~";
} public String add(String obj) {
System.out.println("================这个方法不能被切。。。============== \n");
return obj + ":瞄~ 嘿嘿!";
} public String modify(String obj) {
System.out.println("=================这个也设置加入切吧====================\n");
return obj + ":瞄改瞄啊!";
} }

3. 定义切点

package com.chzhao.spring.aoptest;

import java.lang.reflect.Method;

import org.springframework.aop.support.NameMatchMethodPointcut;

/**
* 定义一个切点,指定对应方法匹配。来供切面来针对方法进行处理<br>
*
* 继承NameMatchMethodPointcut类,来用方法名匹配
*
*/
public class Pointcut extends NameMatchMethodPointcut { private static final long serialVersionUID = 3990456017285944475L; @SuppressWarnings("rawtypes")
@Override
public boolean matches(Method method, Class targetClass) {
// 设置单个方法匹配
this.setMappedName("delete");
// 设置多个方法匹配
String[] methods = { "delete", "modify" }; // 也可以用“ * ” 来做匹配符号
// this.setMappedName("get*"); this.setMappedNames(methods);
return super.matches(method, targetClass);
} }

4. Before

package com.chzhao.spring.aoptest;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class BaseBeforeAdvice implements MethodBeforeAdvice {

	public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("===========进入beforeAdvice()============ \n");
System.out.print("准备在" + target + "对象上用");
System.out.print(method + "方法进行对 '");
System.out.print(args[0] + "'进行删除!\n\n");
System.out.println("要进入切入点方法了 \n");
} }

5. AfterReturn

package com.chzhao.spring.aoptest;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class BaseAfterReturnAdvice implements AfterReturningAdvice {

	/**
* returnValue :切入点执行完方法的返回值,但不能修改 <br>
* method :切入点方法 <br>
* args :切入点方法的参数数组 <br>
* target :目标对象
*/ public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("==========进入afterReturning()=========== \n");
System.out.println("切入点方法执行完了 \n");
System.out.print(args[0] + "在");
System.out.print(target + "对象上被");
System.out.print(method + "方法删除了");
System.out.print("只留下:" + returnValue + "\n\n");
} }

6. AfterThrow

package com.chzhao.spring.aoptest;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class BaseAfterThrowsAdvice implements ThrowsAdvice {

	/**
* 通知方法,需要按照这种格式书写
*
* @param method
* 可选:切入的方法
* @param args
* 可选:切入的方法的参数
* @param target
* 可选:目标对象
* @param throwable
* 必填 : 异常子类,出现这个异常类的子类,则会进入这个通知。
*/
public void afterThrowing(Method method, Object[] args, Object target,
Throwable throwable) {
System.out.println("删除出错啦");
} }

7. Around

package com.chzhao.spring.aoptest;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; public class BaseAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("===========进入around环绕方法!=========== \n");
// 调用目标方法之前执行的动作
System.out.println("调用方法之前: 执行!\n");
// 调用方法的参数
Object[] args = invocation.getArguments();
// 调用的方法
Method method = invocation.getMethod();
// 获取目标对象
Object target = invocation.getThis();
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
Object returnValue = invocation.proceed();
System.out.println("===========结束进入around环绕方法!=========== \n");
System.out.println("输出:" + args[0] + ";" + method + ";" + target + ";"
+ returnValue + "\n");
System.out.println("调用方法结束:之后执行!\n");
return returnValue;
} public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable { return null;
} }

8. 主方法

package com.chzhao.spring.aoptest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class AopMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
IBaseBusiness business = (IBaseBusiness ) context.getBean("businessProxy");
business.delete("猫");
}
}

9. 最重要的配置文件

<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName"> <!-- ==============================利用spring自己的aop配置================================ -->
<!-- 声明一个业务类 -->
<bean id="baseBusiness" class="com.chzhao.spring.aoptest.BaseBusiness" /> <!-- 声明通知类 -->
<bean id="baseBefore" class="com.chzhao.spring.aoptest.BaseBeforeAdvice" />
<bean id="baseAfterReturn" class="com.chzhao.spring.aoptest.BaseAfterReturnAdvice" />
<bean id="baseAfterThrows" class="com.chzhao.spring.aoptest.BaseAfterThrowsAdvice" />
<bean id="baseAround" class="com.chzhao.spring.aoptest.BaseAroundAdvice" /> <!-- 指定切点匹配类 -->
<bean id="pointcut" class="com.chzhao.spring.aoptest.Pointcut" /> <!-- 包装通知,指定切点 -->
<bean id="matchBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="pointcut" />
</property>
<property name="advice">
<ref bean="baseBefore" />
</property>
</bean> <!-- 使用ProxyFactoryBean 产生代理对象 -->
<bean id="businessProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理对象所实现的接口 ,如果有接口可以这样设置 -->
<property name="proxyInterfaces">
<value>com.chzhao.spring.aoptest.IBaseBusiness</value>
</property> <!-- 设置目标对象 -->
<property name="target">
<ref local="baseBusiness" />
</property>
<!-- 代理对象所使用的拦截器 -->
<property name="interceptorNames">
<list>
<value>matchBeforeAdvisor</value>
<value>baseAfterReturn</value>
</list>
</property>
</bean>
</beans>

4. 参考资料

Spring In Action 第三版

aop的常见术语以及aop中常见通知的实现的总结

Spring AOP 学习例子

Spring入门(9)-AOP初探的更多相关文章

  1. Spring入门4.AOP配置深入

    Spring入门4.AOP配置深入 代码下载 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 之前学习AOP中的一些概念,包括连接点.切入点(pointc ...

  2. Spring入门3.AOP编程

    Spring入门3.AOP编程 代码下载: 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 前面学习的知识是Spring在Java项目中的IoC或DJ,这 ...

  3. Spring入门篇——AOP基本概念

    1.什么是AOP及实现方式 什么是AOP AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 主要 ...

  4. Spring入门介绍-AOP(三)

    AOP的概念 AOP是面向切面编程的缩写,它是一种编程的新思想.对我们经常提起的oop(面对对象编程)有一定的联系. AOP和OOP的关系 AOP可以说是oop的某一方便的补充,oop侧重于对静态的属 ...

  5. Spring入门之AOP篇

    听了几节IT黑马营的SPRING课程,照着例程写了一个SPRING 中AOP的例子:  一.准备工作 下载复制或配置JAR包.图方便,我将下载的SPRING包都加上去了.另外还需要aspectj的两个 ...

  6. Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After

    零.准备知识 1)AOP相关概念:Aspect.Advice.Join point.Pointcut.Weaving.Target等. ref: https://www.cnblogs.com/zha ...

  7. Spring入门导读——IoC和AOP

    和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(I ...

  8. Spring框架入门之AOP

    Spring框架入门之AOP 一.Spring AOP简单介绍 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented ...

  9. Spring入门IOC和AOP学习笔记

    Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容 ...

随机推荐

  1. hdu 4901 The Romantic Hero (dp)

    题目链接 题意:给一个数组a,从中选择一些元素,构成两个数组s, t,使s数组里的所有元素异或 等于 t数组里的所有元素 位于,求有多少种构成方式.要求s数组里 的所有的元素的下标 小于 t数组里的所 ...

  2. UVa 12661 (单源最短路) Funny Car Racing

    题意: 有一个赛车跑道,可以看做一个加权有向图.每个跑道(有向边)还有一个特点就是,会周期性地打开a秒,然后关闭b秒.只有在赛车进入一直到出来,该跑道一直处于打开状态,赛车才能通过. 开始时所有跑道处 ...

  3. CentOS 5.6 netInstall可以的在线安装方式。

    之前百度google了一把, 发现原来的地址都失效了. 只找到一个能用的. 下载9M多的CentOS Net Install ISO文件,  选择安装方式时选HTTP. 然后在后面的 服务器位置处输入 ...

  4. ti processor sdk linux am335x evm /bin/setup-tftp.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/setup-tftp.sh hacking # 说明: # 本文主要对TI的sdk中的setu ...

  5. Java [Leetcode 225]Implement Stack using Queues

    题目描述: Implement the following operations of a stack using queues. push(x) -- Push element x onto sta ...

  6. 两个简单的python文件,实现删除本地文件夹和mongodb数据库的内容

    删除本地文件夹: import os , string , datetime ; str = '/home/niuguoqin/tmp/tomcat/'; b = (datetime.datetime ...

  7. 转载:浅析Java中的final关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...

  8. mysql 基础命令入门学习

    登陆到mysql mysql -u 用户名 -p [数据库]   显示数据库 show databases;   使用一个数据库 use 数据库名;   显示表 show tables;   纠正数据 ...

  9. 在PHP中如何获取用户的真实IP

    /** * 获得用户的真实IP地址 * * @access public * @return string */ function real_ip() { static $realip = NULL; ...

  10. ch02-HTML的基本概念

    HTML的基本概念 Ch02: HTML的基本概念 1, 标记: 每一组HTML标记,都会被放在"<>"里面,用于控制里面的文字显示效果及其它一些用途. 语法: 开始标 ...